1
0
mirror of https://github.com/eclipse/mosquitto.git synced 2025-05-08 16:52:13 +08:00

Merge branch 'fixes' into mqtt5

This commit is contained in:
Roger A. Light 2019-02-12 17:05:42 +00:00
commit 084062c85e
63 changed files with 1669 additions and 454 deletions

View File

@ -11,7 +11,7 @@ project(mosquitto)
cmake_minimum_required(VERSION 2.8)
# Only for version 3 and up. cmake_policy(SET CMP0042 NEW)
set (VERSION 1.5.5)
set (VERSION 1.5.6)
add_definitions (-DCMAKE -DVERSION=\"${VERSION}\")
@ -51,7 +51,7 @@ option(WITH_TLS_PSK
"Include TLS-PSK support (requires WITH_TLS)?" ON)
option(WITH_EC
"Include Elliptic Curve support (requires WITH_TLS)?" ON)
if (${WITH_TLS} STREQUAL ON)
if (WITH_TLS)
find_package(OpenSSL REQUIRED)
add_definitions("-DWITH_TLS")
@ -62,19 +62,19 @@ if (${WITH_TLS} STREQUAL ON)
if (${WITH_EC} STREQUAL ON)
add_definitions("-DWITH_EC")
endif (${WITH_EC} STREQUAL ON)
else (${WITH_TLS} STREQUAL ON)
else (WITH_TLS)
set (OPENSSL_INCLUDE_DIR "")
endif (${WITH_TLS} STREQUAL ON)
endif (WITH_TLS)
option(WITH_SOCKS "Include SOCKS5 support?" ON)
if (${WITH_SOCKS} STREQUAL ON)
if (WITH_SOCKS)
add_definitions("-DWITH_SOCKS")
endif (${WITH_SOCKS} STREQUAL ON)
endif (WITH_SOCKS)
option(WITH_SRV "Include SRV lookup support?" OFF)
option(WITH_THREADING "Include client library threading support?" ON)
if (${WITH_THREADING} STREQUAL ON)
if (WITH_THREADING)
add_definitions("-DWITH_THREADING")
if (WIN32)
if (CMAKE_CL_64)
@ -92,10 +92,10 @@ if (${WITH_THREADING} STREQUAL ON)
endif()
set (PTHREAD_INCLUDE_DIR "")
endif (WIN32)
else (${WITH_THREADING} STREQUAL ON)
else (WITH_THREADING)
set (PTHREAD_LIBRARIES "")
set (PTHREAD_INCLUDE_DIR "")
endif (${WITH_THREADING} STREQUAL ON)
endif (WITH_THREADING)
option(DOCUMENTATION "Build documentation?" ON)
@ -106,9 +106,9 @@ option(DOCUMENTATION "Build documentation?" ON)
add_subdirectory(lib)
add_subdirectory(client)
add_subdirectory(src)
if (${DOCUMENTATION} STREQUAL ON)
if (DOCUMENTATION)
add_subdirectory(man)
endif (${DOCUMENTATION} STREQUAL ON)
endif (DOCUMENTATION)
# ========================================
# Install config file

View File

@ -23,6 +23,78 @@ Client fixes:
QoS>0. This has been fixed.
1.5.7 - 201902xx
================
Broker:
- Fix build failure when using WITH_ADNS=yes
- Ensure that an error occurs if `per_listener_settings true` is given after
other security options. Closes #1149.
- Fix include_dir not sorting config files before loading. This was partially
fixed in 1.5 previously.
Library:
- Fix `mosquitto_topic_matches_sub()` not returning MOSQ_ERR_INVAL for
invalid subscriptions like `topic/#abc`. This only affects the return value,
not the match/no match result, which was already correct.
Build:
- Don't require C99 compiler.
1.5.6 - 20190206
================
Security:
- CVE-2018-12551: If Mosquitto is configured to use a password file for
authentication, any malformed data in the password file will be treated as
valid. This typically means that the malformed data becomes a username and no
password. If this occurs, clients can circumvent authentication and get access
to the broker by using the malformed username. In particular, a blank line
will be treated as a valid empty username. Other security measures are
unaffected. Users who have only used the mosquitto_passwd utility to create
and modify their password files are unaffected by this vulnerability.
Affects version 1.0 to 1.5.5 inclusive.
- CVE-2018-12550: If an ACL file is empty, or has only blank lines or
comments, then mosquitto treats the ACL file as not being defined, which
means that no topic access is denied. Although denying access to all topics
is not a useful configuration, this behaviour is unexpected and could lead
to access being incorrectly granted in some circumstances. This is now
fixed. Affects versions 1.0 to 1.5.5 inclusive.
- CVE-2018-12546. If a client publishes a retained message to a topic that
they have access to, and then their access to that topic is revoked, the
retained message will still be delivered to future subscribers. This
behaviour may be undesirable in some applications, so a configuration option
`check_retain_source` has been introduced to enforce checking of the
retained message source on publish.
Broker:
- Fixed comment handling for config options that have optional arguments.
- Improved documentation around bridge topic remapping.
- Handle mismatched handshakes (e.g. QoS1 PUBLISH with QoS2 reply) properly.
- Fix spaces not being allowed in the bridge remote_username option. Closes
#1131.
- Allow broker to always restart on Windows when using `log_dest file`. Closes
#1080.
- Fix Will not being sent for Websockets clients. Closes #1143.
- Windows: Fix possible crash when client disconnects. Closes #1137.
- Fixed durable clients being unable to receive messages when offline, when
per_listener_settings was set to true. Closes #1081.
- Add log message for the case where a client is disconnected for sending a
topic with invalid UTF-8. Closes #1144.
Library:
- Fix TLS connections not working over SOCKS.
- Don't clear SSL context when TLS connection is closed, meaning if a user
provided an external SSL_CTX they have less chance of leaking references.
Build:
- Fix comparison of boolean values in CMake build. Closes #1101.
- Fix compilation when openssl deprecated APIs are not available.
Closes #1094.
- Man pages can now be built on any system. Closes #1139.
1.5.5 - 20181211
================
@ -30,6 +102,7 @@ Security:
- If `per_listener_settings` is set to true, then the `acl_file` setting was
ignored for the "default listener" only. This has been fixed. This does not
affect any listeners defined with the `listener` option. Closes #1073.
This is now tracked as CVE-2018-20145.
Broker:
- Add `socket_domain` option to allow listeners to disable IPv6 support.

View File

@ -1,12 +1,13 @@
include_directories(${mosquitto_SOURCE_DIR} ${mosquitto_SOURCE_DIR}/lib
${STDBOOL_H_PATH} ${STDINT_H_PATH} ${PTHREAD_INCLUDE_DIR})
${STDBOOL_H_PATH} ${STDINT_H_PATH} ${PTHREAD_INCLUDE_DIR}
${OPENSSL_INCLUDE_DIR})
link_directories(${mosquitto_BINARY_DIR}/lib)
set(shared_src client_shared.c client_shared.h client_props.c)
if (${WITH_SRV} STREQUAL ON)
if (WITH_SRV)
add_definitions("-DWITH_SRV")
endif (${WITH_SRV} STREQUAL ON)
endif (WITH_SRV)
add_executable(mosquitto_pub pub_client.c pub_shared.c ${shared_src})
add_executable(mosquitto_sub sub_client.c sub_client_output.c ${shared_src})

View File

@ -20,10 +20,10 @@ static : static_pub static_sub
# This makes mosquitto_pub/sub versions that are statically linked with
# libmosquitto only.
static_pub : pub_client.o pub_shared.o client_shared.o ../lib/libmosquitto.a
static_pub : pub_client.o pub_shared.o client_props.o client_shared.o ../lib/libmosquitto.a
${CROSS_COMPILE}${CC} $^ -o mosquitto_pub ${CLIENT_LDFLAGS} -lssl -lcrypto -lpthread
static_sub : sub_client.o sub_client_output.o client_shared.o ../lib/libmosquitto.a
static_sub : sub_client.o sub_client_output.o client_props.o client_shared.o ../lib/libmosquitto.a
${CROSS_COMPILE}${CC} $^ -o mosquitto_sub ${CLIENT_LDFLAGS} -lssl -lcrypto -lpthread
mosquitto_pub : pub_client.o pub_shared.o client_shared.o client_props.o

View File

@ -35,7 +35,9 @@ Contributors:
#include <mqtt_protocol.h>
#include "client_shared.h"
#ifdef WITH_SOCKS
static int mosquitto__parse_socks_url(struct mosq_config *cfg, char *url);
#endif
static int client_config_line_proc(struct mosq_config *cfg, int pub_or_sub, int argc, char *argv[]);
@ -945,7 +947,9 @@ unknown_option:
int client_opts_set(struct mosquitto *mosq, struct mosq_config *cfg)
{
#ifdef WITH_SOCKS
int rc;
#endif
mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, cfg->protocol_version);

View File

@ -104,13 +104,13 @@ WITH_COVERAGE:=no
# Also bump lib/mosquitto.h, CMakeLists.txt,
# installer/mosquitto.nsi, installer/mosquitto64.nsi
VERSION=1.5.5
VERSION=1.5.6
# Client library SO version. Bump if incompatible API/ABI changes are made.
SOVERSION=1
# Man page generation requires xsltproc and docbook-xsl
XSLTPROC=xsltproc
XSLTPROC=xsltproc --nonet
# For html generation
DB_HTML_XSL=man/html.xsl

View File

@ -3,8 +3,8 @@ FROM alpine:3.8
LABEL maintainer="Roger Light <roger@atchoo.org>" \
description="Eclipse Mosquitto MQTT Broker"
ENV VERSION=1.5.5 \
DOWNLOAD_SHA256=fcdb47e340864c545146681af7253399cc292e41775afd76400fda5b0d23d668 \
ENV VERSION=1.5.6 \
DOWNLOAD_SHA256=d5bdc13cc668350026376d57fc14de10aaee029f6840707677637d15e0751a40 \
GPG_KEYS=A0D6EEA1DCAE49A635A3B2F0779B22DFB3E717B7 \
LWS_VERSION=2.4.2

View File

@ -9,7 +9,7 @@
!define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
Name "Eclipse Mosquitto"
!define VERSION 1.5.5
!define VERSION 1.5.6
OutFile "mosquitto-${VERSION}-install-windows-x86.exe"
InstallDir "$PROGRAMFILES\mosquitto"

View File

@ -9,7 +9,7 @@
!define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
Name "Eclipse Mosquitto"
!define VERSION 1.5.5
!define VERSION 1.5.6
OutFile "mosquitto-${VERSION}-install-windows-x64.exe"
!include "x64.nsh"

View File

@ -63,7 +63,7 @@ if (WIN32)
set (LIBRARIES ${LIBRARIES} ws2_32)
endif (WIN32)
if (${WITH_SRV} STREQUAL ON)
if (WITH_SRV)
# Simple detect c-ares
find_path(ARES_HEADER ares.h)
if (ARES_HEADER)
@ -72,7 +72,7 @@ if (${WITH_SRV} STREQUAL ON)
else (ARES_HEADER)
message(WARNING "c-ares library not found.")
endif (ARES_HEADER)
endif (${WITH_SRV} STREQUAL ON)
endif (WITH_SRV)
add_library(libmosquitto SHARED ${C_SRC})
set_target_properties(libmosquitto PROPERTIES
@ -89,13 +89,13 @@ set_target_properties(libmosquitto PROPERTIES
install(TARGETS libmosquitto RUNTIME DESTINATION "${BINDIR}" LIBRARY DESTINATION "${LIBDIR}")
if (${WITH_STATIC_LIBRARIES} STREQUAL ON)
if (WITH_STATIC_LIBRARIES)
add_library(libmosquitto_static STATIC ${C_SRC})
if (${WITH_PIC} STREQUAL ON)
if (WITH_PIC)
set_target_properties(libmosquitto_static PROPERTIES
POSITION_INDEPENDENT_CODE 1
)
endif (${WITH_PIC} STREQUAL ON)
endif (WITH_PIC)
target_link_libraries(libmosquitto_static ${LIBRARIES})
@ -106,7 +106,7 @@ if (${WITH_STATIC_LIBRARIES} STREQUAL ON)
target_compile_definitions(libmosquitto_static PUBLIC "LIBMOSQUITTO_STATIC")
install(TARGETS libmosquitto_static RUNTIME DESTINATION "${BINDIR}" ARCHIVE DESTINATION "${LIBDIR}")
endif (${WITH_STATIC_LIBRARIES} STREQUAL ON)
endif (WITH_STATIC_LIBRARIES)
install(FILES mosquitto.h DESTINATION "${INCLUDEDIR}")

View File

@ -15,16 +15,16 @@ set_target_properties(mosquittopp PROPERTIES
)
install(TARGETS mosquittopp RUNTIME DESTINATION "${BINDIR}" LIBRARY DESTINATION "${LIBDIR}")
if (${WITH_STATIC_LIBRARIES} STREQUAL ON)
if (WITH_STATIC_LIBRARIES)
add_library(mosquittopp_static STATIC
${C_SRC}
${CPP_SRC}
)
if (${WITH_PIC} STREQUAL ON)
if (WITH_PIC)
set_target_properties(mosquittopp_static PROPERTIES
POSITION_INDEPENDENT_CODE 1
)
endif (${WITH_PIC} STREQUAL ON)
endif (WITH_PIC)
target_link_libraries(mosquittopp_static ${LIBRARIES})
@ -35,7 +35,7 @@ if (${WITH_STATIC_LIBRARIES} STREQUAL ON)
target_compile_definitions(mosquittopp_static PUBLIC "LIBMOSQUITTO_STATIC")
install(TARGETS mosquittopp_static RUNTIME DESTINATION "${BINDIR}" ARCHIVE DESTINATION "${LIBDIR}")
endif (${WITH_STATIC_LIBRARIES} STREQUAL ON)
endif (WITH_STATIC_LIBRARIES)
install(FILES mosquittopp.h DESTINATION "${INCLUDEDIR}")

View File

@ -46,10 +46,12 @@ int handle__pubackcomp(struct mosquitto *mosq, const char *type)
uint16_t mid;
int rc;
mosquitto_property *properties = NULL;
int qos;
assert(mosq);
rc = packet__read_uint16(&mosq->in_packet, &mid);
if(rc) return rc;
qos = type[3] == 'A'?1:2; /* pubAck or pubComp */
if(mid == 0) return MOSQ_ERR_PROTOCOL;
if(mosq->protocol == mosq_p_mqtt5 && mosq->in_packet.remaining_length > 2){
@ -69,7 +71,7 @@ int handle__pubackcomp(struct mosquitto *mosq, const char *type)
mosquitto_property_free_all(&properties);
if(mid){
rc = db__message_delete(db, mosq, mid, mosq_md_out);
rc = db__message_delete(db, mosq, mid, mosq_md_out, mosq_ms_wait_for_pubcomp, qos);
if(rc == MOSQ_ERR_NOT_FOUND){
log__printf(mosq, MOSQ_LOG_WARNING, "Warning: Received %s from %s for an unknown packet identifier %d.", type, mosq->id, mid);
return MOSQ_ERR_SUCCESS;
@ -80,7 +82,10 @@ int handle__pubackcomp(struct mosquitto *mosq, const char *type)
#else
log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received %s (Mid: %d)", mosq->id, type, mid);
if(!message__delete(mosq, mid, mosq_md_out)){
rc = message__delete(mosq, mid, mosq_md_out, qos);
if(rc){
return rc;
}else{
/* Only inform the client the message has been sent once. */
pthread_mutex_lock(&mosq->callback_mutex);
if(mosq->on_publish){

View File

@ -63,17 +63,17 @@ int handle__pubrec(struct mosquitto_db *db, struct mosquitto *mosq)
log__printf(NULL, MOSQ_LOG_DEBUG, "Received PUBREC from %s (Mid: %d)", mosq->id, mid);
if(reason_code < 0x80){
rc = db__message_update(mosq, mid, mosq_md_out, mosq_ms_wait_for_pubcomp);
rc = db__message_update(mosq, mid, mosq_md_out, mosq_ms_wait_for_pubcomp, 2);
}else{
return db__message_delete(db, mosq, mid, mosq_md_out);
return db__message_delete(db, mosq, mid, mosq_md_out, mosq_ms_wait_for_pubrec, 2);
}
#else
log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PUBREC (Mid: %d)", mosq->id, mid);
if(reason_code < 0x80){
rc = message__out_update(mosq, mid, mosq_ms_wait_for_pubcomp);
rc = message__out_update(mosq, mid, mosq_ms_wait_for_pubcomp, 2);
}else{
if(!message__delete(mosq, mid, mosq_md_out)){
if(!message__delete(mosq, mid, mosq_md_out, 2)){
/* Only inform the client the message has been sent once. */
pthread_mutex_lock(&mosq->callback_mutex);
if(mosq->on_publish_v5){

View File

@ -72,7 +72,10 @@ int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq)
/* Immediately free, we don't do anything with Reason String or User Property at the moment */
mosquitto_property_free_all(&properties);
if(db__message_release(db, mosq, mid, mosq_md_in)){
rc = db__message_release(db, mosq, mid, mosq_md_in);
if(rc == MOSQ_ERR_PROTOCOL){
return rc;
}else if(rc != MOSQ_ERR_SUCCESS){
/* Message not found. Still send a PUBCOMP anyway because this could be
* due to a repeated PUBREL after a client has reconnected. */
log__printf(mosq, MOSQ_LOG_WARNING, "Warning: Received PUBREL from %s for an unknown packet identifier %d.", mosq->id, mid);
@ -85,11 +88,14 @@ int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq)
rc = send__pubcomp(mosq, mid);
if(rc){
message__remove(mosq, mid, mosq_md_in, &message);
message__remove(mosq, mid, mosq_md_in, &message, 2);
return rc;
}
if(!message__remove(mosq, mid, mosq_md_in, &message)){
rc = message__remove(mosq, mid, mosq_md_in, &message, 2);
if(rc){
return rc;
}else{
/* Only pass the message on if we have removed it from the queue - this
* prevents multiple callbacks for the same message. */
pthread_mutex_lock(&mosq->callback_mutex);

View File

@ -83,13 +83,13 @@ int mosquitto_message_copy(struct mosquitto_message *dst, const struct mosquitto
return MOSQ_ERR_SUCCESS;
}
int message__delete(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir)
int message__delete(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, int qos)
{
struct mosquitto_message_all *message;
int rc;
assert(mosq);
rc = message__remove(mosq, mid, dir, &message);
rc = message__remove(mosq, mid, dir, &message, qos);
if(rc == MOSQ_ERR_SUCCESS){
message__cleanup(&message);
}
@ -216,7 +216,7 @@ void message__reconnect_reset(struct mosquitto *mosq)
pthread_mutex_unlock(&mosq->out_message_mutex);
}
int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, struct mosquitto_message_all **message)
int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, struct mosquitto_message_all **message, int qos)
{
struct mosquitto_message_all *cur, *prev = NULL;
bool found = false;
@ -229,6 +229,9 @@ int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_dir
cur = mosq->out_messages;
while(cur){
if(cur->msg.mid == mid){
if(cur->msg.qos != qos){
return MOSQ_ERR_PROTOCOL;
}
if(prev){
prev->next = cur->next;
}else{
@ -283,6 +286,9 @@ int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_dir
cur = mosq->in_messages;
while(cur){
if(cur->msg.mid == mid){
if(cur->msg.qos != qos){
return MOSQ_ERR_PROTOCOL;
}
if(prev){
prev->next = cur->next;
}else{
@ -366,7 +372,7 @@ void mosquitto_message_retry_set(struct mosquitto *mosq, unsigned int message_re
{
}
int message__out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_state state)
int message__out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_state state, int qos)
{
struct mosquitto_message_all *message;
assert(mosq);
@ -375,6 +381,9 @@ int message__out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg
message = mosq->out_messages;
while(message){
if(message->msg.mid == mid){
if(message->msg.qos != qos){
return MOSQ_ERR_PROTOCOL;
}
message->state = state;
message->timestamp = mosquitto_time();
pthread_mutex_unlock(&mosq->out_message_mutex);

View File

@ -21,11 +21,11 @@ Contributors:
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 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);
int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, struct mosquitto_message_all **message);
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);
int message__out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_state state);
int message__out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_state state, int qos);
#endif

View File

@ -48,7 +48,7 @@ extern "C" {
#define LIBMOSQUITTO_MAJOR 1
#define LIBMOSQUITTO_MINOR 5
#define LIBMOSQUITTO_REVISION 5
#define LIBMOSQUITTO_REVISION 6
/* 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)

View File

@ -220,8 +220,7 @@ struct mosquitto {
bool clean_start;
uint32_t session_expiry_interval;
#ifdef WITH_BROKER
char *old_id; /* for when a duplicate client connects, but we still want to
know what the id was */
bool removed_from_by_id; /* True if removed from by_id hash */
bool is_dropping;
bool is_bridge;
struct mosquitto__bridge *bridge;

View File

@ -87,9 +87,11 @@ int net__init(void)
#endif
#ifdef WITH_TLS
# if OPENSSL_VERSION_NUMBER < 0x10100000L || OPENSSL_API_COMPAT < 0x10100000L
SSL_load_error_strings();
SSL_library_init();
OpenSSL_add_all_algorithms();
# endif
if(tls_ex_index_mosq == -1){
tls_ex_index_mosq = SSL_get_ex_new_index(0, "client context", NULL, NULL, NULL);
}
@ -100,16 +102,18 @@ int net__init(void)
void net__cleanup(void)
{
#ifdef WITH_TLS
#if OPENSSL_VERSION_NUMBER < 0x10100000L
ERR_remove_state(0);
#endif
#ifndef OPENSSL_NO_ENGINE
ENGINE_cleanup();
#endif
CONF_modules_unload(1);
ERR_free_strings();
EVP_cleanup();
# if OPENSSL_VERSION_NUMBER < 0x10100000L || OPENSSL_API_COMPAT < 0x10100000L
CRYPTO_cleanup_all_ex_data();
ERR_free_strings();
ERR_remove_state(0);
EVP_cleanup();
# if !defined(OPENSSL_NO_ENGINE)
ENGINE_cleanup();
# endif
# endif
CONF_modules_unload(1);
#endif
#ifdef WITH_SRV
@ -145,10 +149,6 @@ int net__socket_close(struct mosquitto *mosq)
SSL_free(mosq->ssl);
mosq->ssl = NULL;
}
if(mosq->ssl_ctx){
SSL_CTX_free(mosq->ssl_ctx);
mosq->ssl_ctx = NULL;
}
}
#endif
@ -162,7 +162,7 @@ int net__socket_close(struct mosquitto *mosq)
}else
#endif
{
if((int)mosq->sock >= 0){
if(mosq->sock != INVALID_SOCKET){
#ifdef WITH_BROKER
HASH_DELETE(hh_sock, db->contexts_by_sock, mosq);
#endif
@ -174,8 +174,6 @@ int net__socket_close(struct mosquitto *mosq)
#ifdef WITH_BROKER
if(mosq->listener){
mosq->listener->client_count--;
assert(mosq->listener->client_count >= 0);
mosq->listener = NULL;
}
#endif
@ -606,7 +604,7 @@ static int net__init_ssl_ctx(struct mosquitto *mosq)
#endif
int net__socket_connect_step3(struct mosquitto *mosq, const char *host, uint16_t port, const char *bind_address, bool blocking)
int net__socket_connect_step3(struct mosquitto *mosq, const char *host)
{
#ifdef WITH_TLS
BIO *bio;
@ -667,8 +665,13 @@ int net__socket_connect(struct mosquitto *mosq, const char *host, uint16_t port,
mosq->sock = sock;
rc = net__socket_connect_step3(mosq, host, port, bind_address, blocking);
if(rc) return rc;
#if defined(WITH_SOCKS) && !defined(WITH_BROKER)
if(!mosq->socks5_host)
#endif
{
rc = net__socket_connect_step3(mosq, host);
if(rc) return rc;
}
return MOSQ_ERR_SUCCESS;
}

View File

@ -61,7 +61,7 @@ int net__socket_close(struct mosquitto *mosq);
int net__try_connect(struct mosquitto *mosq, const char *host, uint16_t port, mosq_sock_t *sock, const char *bind_address, bool blocking);
int net__try_connect_step1(struct mosquitto *mosq, const char *host);
int net__try_connect_step2(struct mosquitto *mosq, uint16_t port, mosq_sock_t *sock);
int net__socket_connect_step3(struct mosquitto *mosq, const char *host, uint16_t port, const char *bind_address, bool blocking);
int net__socket_connect_step3(struct mosquitto *mosq, const char *host);
int net__socket_nonblock(mosq_sock_t *sock);
int net__socketpair(mosq_sock_t *sp1, mosq_sock_t *sp2);

View File

@ -141,7 +141,7 @@ int packet__queue(struct mosquitto *mosq, struct mosquitto__packet *packet)
#endif
}
if(mosq->in_callback == false && mosq->threaded == false){
if(mosq->in_callback == false && mosq->threaded == mosq_ts_none){
return packet__write(mosq);
}else{
return MOSQ_ERR_SUCCESS;
@ -265,8 +265,12 @@ int packet__read(struct mosquitto *mosq)
ssize_t read_length;
int rc = 0;
if(!mosq) return MOSQ_ERR_INVAL;
if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN;
if(!mosq){
return MOSQ_ERR_INVAL;
}
if(mosq->sock == INVALID_SOCKET){
return MOSQ_ERR_NO_CONN;
}
if(mosq->state == mosq_cs_connect_pending){
return MOSQ_ERR_SUCCESS;
}
@ -292,10 +296,14 @@ int packet__read(struct mosquitto *mosq)
#ifdef WITH_BROKER
G_BYTES_RECEIVED_INC(1);
/* Clients must send CONNECT as their first command. */
if(!(mosq->bridge) && mosq->state == mosq_cs_new && (byte&0xF0) != CMD_CONNECT) return MOSQ_ERR_PROTOCOL;
if(!(mosq->bridge) && mosq->state == mosq_cs_new && (byte&0xF0) != CMD_CONNECT){
return MOSQ_ERR_PROTOCOL;
}
#endif
}else{
if(read_length == 0) return MOSQ_ERR_CONN_LOST; /* EOF */
if(read_length == 0){
return MOSQ_ERR_CONN_LOST; /* EOF */
}
#ifdef WIN32
errno = WSAGetLastError();
#endif
@ -328,13 +336,17 @@ int packet__read(struct mosquitto *mosq)
/* Max 4 bytes length for remaining length as defined by protocol.
* Anything more likely means a broken/malicious client.
*/
if(mosq->in_packet.remaining_count < -4) return MOSQ_ERR_PROTOCOL;
if(mosq->in_packet.remaining_count < -4){
return MOSQ_ERR_PROTOCOL;
}
G_BYTES_RECEIVED_INC(1);
mosq->in_packet.remaining_length += (byte & 127) * mosq->in_packet.remaining_mult;
mosq->in_packet.remaining_mult *= 128;
}else{
if(read_length == 0) return MOSQ_ERR_CONN_LOST; /* EOF */
if(read_length == 0){
return MOSQ_ERR_CONN_LOST; /* EOF */
}
#ifdef WIN32
errno = WSAGetLastError();
#endif
@ -356,7 +368,9 @@ int packet__read(struct mosquitto *mosq)
if(mosq->in_packet.remaining_length > 0){
mosq->in_packet.payload = mosquitto__malloc(mosq->in_packet.remaining_length*sizeof(uint8_t));
if(!mosq->in_packet.payload) return MOSQ_ERR_NOMEM;
if(!mosq->in_packet.payload){
return MOSQ_ERR_NOMEM;
}
mosq->in_packet.to_process = mosq->in_packet.remaining_length;
}
}

View File

@ -424,6 +424,10 @@ int socks5__read(struct mosquitto *mosq)
/* Auth passed */
packet__cleanup(&mosq->in_packet);
mosq->state = mosq_cs_new;
if(mosq->socks5_host){
int rc = net__socket_connect_step3(mosq, mosq->host);
if(rc) return rc;
}
return send__connect(mosq, mosq->keepalive, mosq->clean_start, NULL);
}else{
i = mosq->in_packet.payload[1];

View File

@ -28,6 +28,9 @@ Contributors:
# include <sys/stat.h>
#endif
#ifdef WITH_TLS
# include <openssl/bn.h>
#endif
#ifdef WITH_BROKER
#include "mosquitto_broker_internal.h"
@ -86,11 +89,6 @@ int mosquitto__check_keepalive(struct mosquitto *mosq)
pthread_mutex_unlock(&mosq->msgtime_mutex);
}else{
#ifdef WITH_BROKER
if(mosq->listener){
mosq->listener->client_count--;
assert(mosq->listener->client_count >= 0);
}
mosq->listener = NULL;
net__socket_close(db, mosq);
#else
net__socket_close(mosq);
@ -195,6 +193,21 @@ FILE *mosquitto__fopen(const char *path, const char *mode, bool restrict_read)
char username[UNLEN + 1];
int ulen = UNLEN;
SECURITY_DESCRIPTOR sd;
DWORD dwCreationDisposition;
switch(mode[0]){
case 'a':
dwCreationDisposition = OPEN_ALWAYS;
break;
case 'r':
dwCreationDisposition = OPEN_EXISTING;
break;
case 'w':
dwCreationDisposition = CREATE_ALWAYS;
break;
default:
return NULL;
}
GetUserName(username, &ulen);
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
@ -215,7 +228,7 @@ FILE *mosquitto__fopen(const char *path, const char *mode, bool restrict_read)
hfile = CreateFile(buf, GENERIC_READ | GENERIC_WRITE, 0,
&sec,
CREATE_NEW,
dwCreationDisposition,
FILE_ATTRIBUTE_NORMAL,
NULL);

View File

@ -1,6 +1,6 @@
<!-- Set parameters for manpage xsl -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="/usr/share/xml/docbook/stylesheet/docbook-xsl/html/docbook.xsl"/>
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl"/>
<xsl:output encoding="utf-8" indent="yes"/>
<xsl:param name="html.stylesheet">man.css</xsl:param>
<!-- Generate ansi style function synopses. -->

View File

@ -1,6 +1,6 @@
<!-- Set parameters for manpage xsl -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="/usr/share/xml/docbook/stylesheet/docbook-xsl/manpages/docbook.xsl"/>
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl"/>
<xsl:strip-space elements="member"/>
<!-- Don't display notes list of link urls. -->
<xsl:param name="man.endnotes.list.enabled">0</xsl:param>

View File

@ -64,15 +64,17 @@
certificate in order to connect successfully. In this case, the
second and third options, use_identity_as_username and
use_subject_as_username, become relevant. If set to true,
use_identity_as_user causes the Common Name (CN) from the client
certificate to be used instead of the MQTT username for access
control purposes. The password is not replaced because it is
assumed that only authenticated clients have valid certificates. If
use_identity_as_username is false, the client must authenticate as
normal (if required by password_file) through the MQTT options. The
same principle applies for the use_subject_as_username option, but
the entire certificate subject is used as the username instead of
just the CN.</para>
use_identity_as_username causes the Common Name (CN) from the
client certificate to be used instead of the MQTT username for
access control purposes. The password is not used because it is
assumed that only authenticated clients have valid certificates.
This means that any CA certificates you include in cafile or capath
will be able to issue client certificates that are valid for
connecting to your broker. If use_identity_as_username is false,
the client must authenticate as normal (if required by
password_file) through the MQTT options. The same principle applies
for the use_subject_as_username option, but the entire certificate
subject is used as the username instead of just the CN.</para>
<para>When using pre-shared-key based encryption through the psk_hint
and psk_file options, the client must provide a valid identity and
key in order to connect to the broker before any MQTT communication
@ -294,6 +296,24 @@
<para>Reloaded on reload signal.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>check_retain_source</option> [ true | false ]</term>
<listitem>
<para>This option affects the scenario when a client
subscribes to a topic that has retained messages. It is
possible that the client that published the retained
message to the topic had access at the time they
published, but that access has been subsequently
removed. If <option>check_retain_source</option> is set
to true, the default, the source of a retained message
will be checked for access rights before it is
republished. When set to false, no check will be made
and the retained message will always be
published.</para>
<para>This option applies globally, regardless of the
<option>per_listener_settings</option> option.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>clientid_prefixes</option> <replaceable>prefix</replaceable></term>
<listitem>
@ -534,6 +554,10 @@
<option>auth_plugin</option>,
<option>auth_opt_*</option>,
<option>auto_id_prefix</option>.</para>
<para>Note that if set to true, then a durable client (i.e.
with clean session set to false) that has disconnected
will use the ACL settings defined for the listener that
it was most recently connected to.</para>
<para>The default behaviour is for this to be set to
<replaceable>false</replaceable>, which maintains the
settings behaviour from previous versions of
@ -1402,27 +1426,35 @@
<replaceable>""</replaceable>. Using the empty marker
for the topic itself is also valid. The table below
defines what combination of empty or value is
valid.</para>
valid. The <option>Full Local Topic</option> and
<option>Full Remote Topic</option> show the resulting
topics that would be used on the local and remote ends
of the bridge. For example, for the first table row if
you publish to <option>L/topic</option> on the local
broker, then the remote broker will receive a message
on the topic <option>R/topic</option>.</para>
<informaltable>
<tgroup cols="5">
<tgroup cols="6">
<thead>
<row>
<entry></entry>
<entry><emphasis>Topic</emphasis></entry>
<entry><emphasis>Pattern</emphasis></entry>
<entry><emphasis>Local Prefix</emphasis></entry>
<entry><emphasis>Remote Prefix</emphasis></entry>
<entry><emphasis>Validity</emphasis></entry>
<entry><emphasis>Full Local Topic</emphasis></entry>
<entry><emphasis>Full Remote Topic</emphasis></entry>
</row>
</thead>
<tbody>
<row><entry>1</entry><entry>value</entry><entry>value</entry><entry>value</entry><entry>valid</entry></row>
<row><entry>2</entry><entry>value</entry><entry>value</entry><entry>""</entry><entry>valid</entry></row>
<row><entry>3</entry><entry>value</entry><entry>""</entry><entry>value</entry><entry>valid</entry></row>
<row><entry>4</entry><entry>value</entry><entry>""</entry><entry>""</entry><entry>valid (no remapping)</entry></row>
<row><entry>5</entry><entry>""</entry><entry>value</entry><entry>value</entry><entry>valid (remap single local topic to remote)</entry></row>
<row><entry>6</entry><entry>""</entry><entry>value</entry><entry>""</entry><entry>invalid</entry></row>
<row><entry>7</entry><entry>""</entry><entry>""</entry><entry>value</entry><entry>invalid</entry></row>
<row><entry>8</entry><entry>""</entry><entry>""</entry><entry>""</entry><entry>invalid</entry></row>
<row><entry>pattern</entry><entry>L/</entry><entry>R/</entry><entry>valid</entry><entry>L/pattern</entry><entry>R/pattern</entry></row>
<row><entry>pattern</entry><entry>L/</entry><entry>""</entry><entry>valid</entry><entry>L/pattern</entry><entry>pattern</entry></row>
<row><entry>pattern</entry><entry>""</entry><entry>R/</entry><entry>valid</entry><entry>pattern</entry><entry>R/pattern</entry></row>
<row><entry>pattern</entry><entry>""</entry><entry>""</entry><entry>valid (no remapping)</entry><entry>pattern</entry><entry>pattern</entry></row>
<row><entry>""</entry><entry>local</entry><entry>remote</entry><entry>valid (remap single local topic to remote)</entry><entry>local</entry><entry>remote</entry></row>
<row><entry>""</entry><entry>local</entry><entry>""</entry><entry>invalid</entry><entry></entry><entry></entry></row>
<row><entry>""</entry><entry>""</entry><entry>remote</entry><entry>invalid</entry><entry></entry><entry></entry></row>
<row><entry>""</entry><entry>""</entry><entry>""</entry><entry>invalid</entry><entry></entry><entry></entry></row>
</tbody>
</tgroup>
</informaltable>

View File

@ -145,10 +145,23 @@
# password_file acl_file psk_file auth_plugin auth_opt_* allow_anonymous
# auto_id_prefix allow_zero_length_clientid
#
# Note that if set to true, then a durable client (i.e. with clean session set
# to false) that has disconnected will use the ACL settings defined for the
# listener that it was most recently connected to.
#
# The default behaviour is for this to be set to false, which maintains the
# setting behaviour from previous versions of mosquitto.
#per_listener_settings false
# This option affects the scenario when a client subscribes to a topic that has
# retained messages. It is possible that the client that published the retained
# message to the topic had access at the time they published, but that access
# has been subsequently removed. If check_retain_source is set to true, the
# default, the source of a retained message will be checked for access rights
# before it is republished. When set to false, no check will be made and the
# retained message will always be published. This affects all listeners.
#check_retain_source true
# Set to false to disable retained message support. If a client publishes a
# message with the retain bit set, it will be disconnected if this is set to

View File

@ -2,7 +2,7 @@
MAJOR=1
MINOR=5
REVISION=5
REVISION=6
sed -i "s/^VERSION=.*/VERSION=${MAJOR}.${MINOR}.${REVISION}/" config.mk

View File

@ -1,5 +1,5 @@
name: mosquitto
version: 1.5.5
version: 1.5.6
summary: Eclipse Mosquitto MQTT broker
description: This is a message broker that supports version 3.1 and 3.1.1 of the MQTT
protocol.

View File

@ -57,62 +57,62 @@ set (MOSQ_SRCS
option(WITH_BUNDLED_DEPS "Build with bundled dependencies?" ON)
if (${WITH_BUNDLED_DEPS} STREQUAL ON)
if (WITH_BUNDLED_DEPS)
include_directories(${mosquitto_SOURCE_DIR} ${mosquitto_SOURCE_DIR}/src/deps)
endif (${WITH_BUNDLED_DEPS} STREQUAL ON)
endif (WITH_BUNDLED_DEPS)
option(INC_BRIDGE_SUPPORT
"Include bridge support for connecting to other brokers?" ON)
if (${INC_BRIDGE_SUPPORT} STREQUAL ON)
if (INC_BRIDGE_SUPPORT)
set (MOSQ_SRCS ${MOSQ_SRCS} bridge.c)
add_definitions("-DWITH_BRIDGE")
endif (${INC_BRIDGE_SUPPORT} STREQUAL ON)
endif (INC_BRIDGE_SUPPORT)
option(USE_LIBWRAP
"Include tcp-wrappers support?" OFF)
if (${USE_LIBWRAP} STREQUAL ON)
if (USE_LIBWRAP)
set (MOSQ_LIBS ${MOSQ_LIBS} wrap)
add_definitions("-DWITH_WRAP")
endif (${USE_LIBWRAP} STREQUAL ON)
endif (USE_LIBWRAP)
option(INC_DB_UPGRADE
"Include database upgrade support? (recommended)" ON)
option(INC_MEMTRACK
"Include memory tracking support?" ON)
if (${INC_MEMTRACK} STREQUAL ON)
if (INC_MEMTRACK)
add_definitions("-DWITH_MEMORY_TRACKING")
endif (${INC_MEMTRACK} STREQUAL ON)
endif (INC_MEMTRACK)
option(WITH_PERSISTENCE
"Include persistence support?" ON)
if (${WITH_PERSISTENCE} STREQUAL ON)
if (WITH_PERSISTENCE)
add_definitions("-DWITH_PERSISTENCE")
endif (${WITH_PERSISTENCE} STREQUAL ON)
endif (WITH_PERSISTENCE)
option(WITH_SYS_TREE
"Include $SYS tree support?" ON)
if (${WITH_SYS_TREE} STREQUAL ON)
if (WITH_SYS_TREE)
add_definitions("-DWITH_SYS_TREE")
endif (${WITH_SYS_TREE} STREQUAL ON)
endif (WITH_SYS_TREE)
if (CMAKE_SYSTEM_NAME STREQUAL Linux)
option(WITH_SYSTEMD
"Include systemd support?" OFF)
if (${WITH_SYSTEMD} STREQUAL ON)
if (WITH_SYSTEMD)
add_definitions("-DWITH_SYSTEMD")
find_library(SYSTEMD_LIBRARY systemd)
set (MOSQ_LIBS ${MOSQ_LIBS} ${SYSTEMD_LIBRARY})
endif (${WITH_SYSTEMD} STREQUAL ON)
endif (WITH_SYSTEMD)
endif (CMAKE_SYSTEM_NAME STREQUAL Linux)
option(WITH_WEBSOCKETS "Include websockets support?" OFF)
option(STATIC_WEBSOCKETS "Use the static libwebsockets library?" OFF)
if (${WITH_WEBSOCKETS} STREQUAL ON )
if (WITH_WEBSOCKETS)
add_definitions("-DWITH_WEBSOCKETS")
endif (${WITH_WEBSOCKETS} STREQUAL ON)
endif (WITH_WEBSOCKETS)
if (WIN32 OR CYGWIN)
set (MOSQ_SRCS ${MOSQ_SRCS} service.c)
@ -149,17 +149,17 @@ if (WIN32)
set (MOSQ_LIBS ${MOSQ_LIBS} ws2_32)
endif (WIN32)
if (${WITH_WEBSOCKETS} STREQUAL ON)
if (${STATIC_WEBSOCKETS} STREQUAL ON)
if (WITH_WEBSOCKETS)
if (STATIC_WEBSOCKETS)
set (MOSQ_LIBS ${MOSQ_LIBS} websockets_static)
if (WIN32)
set (MOSQ_LIBS ${MOSQ_LIBS} iphlpapi)
link_directories(${mosquitto_SOURCE_DIR})
endif (WIN32)
else (${STATIC_WEBSOCKETS} STREQUAL ON)
else (STATIC_WEBSOCKETS)
set (MOSQ_LIBS ${MOSQ_LIBS} websockets)
endif (${STATIC_WEBSOCKETS} STREQUAL ON)
endif (${WITH_WEBSOCKETS} STREQUAL ON)
endif (STATIC_WEBSOCKETS)
endif (WITH_WEBSOCKETS)
add_executable(mosquitto ${MOSQ_SRCS})
target_link_libraries(mosquitto ${MOSQ_LIBS})
@ -175,14 +175,12 @@ endif (UNIX)
install(TARGETS mosquitto RUNTIME DESTINATION "${SBINDIR}" LIBRARY DESTINATION "${LIBDIR}")
install(FILES mosquitto_broker.h mosquitto_plugin.h DESTINATION "${INCLUDEDIR}")
if (${WITH_TLS} STREQUAL ON)
if (WITH_TLS)
add_executable(mosquitto_passwd mosquitto_passwd.c)
target_link_libraries(mosquitto_passwd ${OPENSSL_LIBRARIES})
install(TARGETS mosquitto_passwd RUNTIME DESTINATION "${BINDIR}" LIBRARY DESTINATION "${LIBDIR}")
endif (${WITH_TLS} STREQUAL ON)
endif (WITH_TLS)
if (UNIX AND NOT APPLE)
install(CODE "EXEC_PROGRAM(/sbin/ldconfig)")
endif (UNIX AND NOT APPLE)

View File

@ -156,7 +156,7 @@ int bridge__connect_step1(struct mosquitto_db *db, struct mosquitto *context)
}
sub__retain_queue(db, context,
context->bridge->topics[i].local_topic,
context->bridge->topics[i].qos);
context->bridge->topics[i].qos, 0);
}
}
@ -164,7 +164,7 @@ int bridge__connect_step1(struct mosquitto_db *db, struct mosquitto *context)
if(context->bridge->notification_topic){
if(!context->bridge->initial_notification_done){
notification_payload = '0';
db__messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, &notification_payload, 1, NULL);
db__messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, &notification_payload, 1, 0, NULL);
context->bridge->initial_notification_done = true;
}
notification_payload = '0';
@ -181,7 +181,7 @@ int bridge__connect_step1(struct mosquitto_db *db, struct mosquitto *context)
if(!context->bridge->initial_notification_done){
notification_payload = '0';
db__messages_easy_queue(db, context, notification_topic, 1, 1, &notification_payload, 1, NULL);
db__messages_easy_queue(db, context, notification_topic, 1, 1, &notification_payload, 1, 0, NULL);
context->bridge->initial_notification_done = true;
}
@ -247,7 +247,7 @@ int bridge__connect_step3(struct mosquitto_db *db, struct mosquitto *context)
{
int rc;
rc = net__socket_connect_step3(context, context->bridge->addresses[context->bridge->cur_address].address, context->bridge->addresses[context->bridge->cur_address].port, NULL, false);
rc = net__socket_connect_step3(context, context->bridge->addresses[context->bridge->cur_address].address);
if(rc > 0){
if(rc == MOSQ_ERR_TLS){
net__socket_close(db, context);

View File

@ -61,6 +61,8 @@ struct config_recurse {
extern SERVICE_STATUS_HANDLE service_handle;
#endif
static struct mosquitto__security_options *cur_security_options = NULL;
static int conf__parse_bool(char **token, const char *name, bool *value, char *saveptr);
static int conf__parse_int(char **token, const char *name, int *value, char *saveptr);
static int conf__parse_ssize_t(char **token, const char *name, ssize_t *value, char *saveptr);
@ -272,7 +274,9 @@ void config__init(struct mosquitto_db *db, struct mosquitto__config *config)
void config__cleanup(struct mosquitto__config *config)
{
int i;
#ifdef WITH_BRIDGE
int j;
#endif
mosquitto__free(config->clientid_prefixes);
mosquitto__free(config->persistence_location);
@ -588,7 +592,9 @@ int config__read(struct mosquitto_db *db, struct mosquitto__config *config, bool
int rc = MOSQ_ERR_SUCCESS;
struct config_recurse cr;
int lineno = 0;
#ifdef WITH_PERSISTENCE
int len;
#endif
struct mosquitto__config config_reload;
int i;
@ -730,20 +736,10 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct
time_t expiration_mult;
char *key;
char *conf_file;
#ifdef WIN32
HANDLE fh;
char dirpath[MAX_PATH];
WIN32_FIND_DATA find_data;
#else
DIR *dh;
struct dirent *de;
#endif
int len;
struct mosquitto__listener *cur_listener = &config->default_listener;
int i;
int lineno_ext;
struct mosquitto__security_options *cur_security_options = NULL;
*lineno = 0;
@ -770,6 +766,9 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct
return MOSQ_ERR_INVAL;
}
while((token = strtok_r(NULL, " ", &saveptr))){
if (token[0] == '#'){
break;
}
cur_bridge->address_count++;
cur_bridge->addresses = mosquitto__realloc(cur_bridge->addresses, sizeof(struct bridge_address)*cur_bridge->address_count);
if(!cur_bridge->addresses){
@ -1094,6 +1093,9 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct
#else
log__printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS support not available.");
#endif
}else if(!strcmp(token, "check_retain_source")){
conf__set_cur_security_options(config, cur_listener, &cur_security_options);
if(conf__parse_bool(&token, "check_retain_source", &config->check_retain_source, saveptr)) return MOSQ_ERR_INVAL;
}else if(!strcmp(token, "ciphers")){
#ifdef WITH_TLS
if(reload) continue; // Listeners not valid for reloading.
@ -1212,66 +1214,27 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct
log__printf(NULL, MOSQ_LOG_ERR, "Error: Empty include_dir value in configuration.");
return 1;
}
#ifdef WIN32
snprintf(dirpath, MAX_PATH, "%s\\*.conf", token);
fh = FindFirstFile(dirpath, &find_data);
if(fh == INVALID_HANDLE_VALUE){
/* No files found */
continue;
}
do{
len = strlen(token)+1+strlen(find_data.cFileName)+1;
conf_file = mosquitto__malloc(len+1);
if(!conf_file){
FindClose(fh);
return MOSQ_ERR_NOMEM;
}
snprintf(conf_file, len, "%s\\%s", token, find_data.cFileName);
conf_file[len] = '\0';
char **files;
int file_count;
rc = config__get_dir_files(token, &files, &file_count);
if(rc) return rc;
rc = config__read_file(config, reload, conf_file, cr, level+1, &lineno_ext);
for(i=0; i<file_count; i++){
log__printf(NULL, MOSQ_LOG_INFO, "Loading config file %s", files[i]);
rc = config__read_file(config, reload, files[i], cr, level+1, &lineno_ext);
if(rc){
FindClose(fh);
log__printf(NULL, MOSQ_LOG_ERR, "Error found at %s:%d.", conf_file, lineno_ext);
mosquitto__free(conf_file);
return rc;
}
mosquitto__free(conf_file);
}while(FindNextFile(fh, &find_data));
FindClose(fh);
#else
dh = opendir(token);
if(!dh){
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open include_dir '%s'.", token);
return 1;
}
while((de = readdir(dh)) != NULL){
if(strlen(de->d_name) > 5){
if(!strcmp(&de->d_name[strlen(de->d_name)-5], ".conf")){
len = strlen(token)+1+strlen(de->d_name)+1;
conf_file = mosquitto__malloc(len+1);
if(!conf_file){
closedir(dh);
return MOSQ_ERR_NOMEM;
}
snprintf(conf_file, len, "%s/%s", token, de->d_name);
conf_file[len] = '\0';
rc = config__read_file(config, reload, conf_file, cr, level+1, &lineno_ext);
if(rc){
closedir(dh);
log__printf(NULL, MOSQ_LOG_ERR, "Error found at %s:%d.", conf_file, lineno_ext);
mosquitto__free(conf_file);
return rc;
}
mosquitto__free(conf_file);
}
log__printf(NULL, MOSQ_LOG_ERR, "Error found at %s:%d.", files[i], lineno_ext);
/* Free happens below */
break;
}
}
closedir(dh);
#endif
for(i=0; i<file_count; i++){
mosquitto__free(files[i]);
}
mosquitto__free(files);
if(rc) return rc; /* This returns if config__read_file() fails above */
}
}else if(!strcmp(token, "keepalive_interval")){
#ifdef WITH_BRIDGE
@ -1332,7 +1295,10 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct
cur_listener->protocol = mp_mqtt;
cur_listener->port = tmp_int;
cur_listener->maximum_qos = 2;
token = strtok_r(NULL, "", &saveptr);
token = strtok_r(NULL, " ", &saveptr);
if (token != NULL && token[0] == '#'){
token = NULL;
}
mosquitto__free(cur_listener->host);
if(token){
cur_listener->host = mosquitto__strdup(token);
@ -1894,6 +1860,9 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct
}
token = strtok_r(NULL, " ", &saveptr);
if(token){
if (token[0] == '#'){
strtok_r(NULL, "", &saveptr);
}
cur_topic->qos = atoi(token);
if(cur_topic->qos < 0 || cur_topic->qos > 2){
log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge QoS level '%s'.", token);
@ -1903,8 +1872,11 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct
token = strtok_r(NULL, " ", &saveptr);
if(token){
cur_bridge->topic_remapping = true;
if(!strcmp(token, "\"\"")){
if(!strcmp(token, "\"\"") || token[0] == '#'){
cur_topic->local_prefix = NULL;
if (token[0] == '#'){
strtok_r(NULL, "", &saveptr);
}
}else{
if(mosquitto_pub_topic_check(token) != MOSQ_ERR_SUCCESS){
log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge topic local prefix '%s'.", token);
@ -1919,7 +1891,7 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct
token = strtok_r(NULL, " ", &saveptr);
if(token){
if(!strcmp(token, "\"\"")){
if(!strcmp(token, "\"\"") || token[0] == '#'){
cur_topic->remote_prefix = NULL;
}else{
if(mosquitto_pub_topic_check(token) != MOSQ_ERR_SUCCESS){
@ -2034,21 +2006,7 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct
log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
return MOSQ_ERR_INVAL;
}
token = strtok_r(NULL, " ", &saveptr);
if(token){
if(cur_bridge->remote_username){
log__printf(NULL, MOSQ_LOG_ERR, "Error: Duplicate username value in bridge configuration.");
return MOSQ_ERR_INVAL;
}
cur_bridge->remote_username = mosquitto__strdup(token);
if(!cur_bridge->remote_username){
log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
return MOSQ_ERR_NOMEM;
}
}else{
log__printf(NULL, MOSQ_LOG_ERR, "Error: Empty username value in configuration.");
return MOSQ_ERR_INVAL;
}
if(conf__parse_string(&token, "bridge remote_username", &cur_bridge->remote_username, saveptr)) return MOSQ_ERR_INVAL;
#else
log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available.");
#endif

View File

@ -46,13 +46,13 @@ Contributors:
#include "util_mosq.h"
#include "mqtt_protocol.h"
int strcasecmp_p(const void *p1, const void *p2)
#ifdef WIN32
int scmp_p(const void *p1, const void *p2)
{
return strcasecmp(*(const char **)p1, *(const char **)p2);
}
#ifdef WIN32
int config__get_dir_files(const char *include_dir, char ***files, int *file_count)
{
int len;
@ -102,6 +102,7 @@ int config__get_dir_files(const char *include_dir, char ***files, int *file_coun
FindClose(fh);
qsort(l_files, l_file_count, sizeof(char *), scmp_p);
*files = l_files;
*file_count = l_file_count;
@ -111,6 +112,11 @@ int config__get_dir_files(const char *include_dir, char ***files, int *file_coun
#ifndef WIN32
int scmp_p(const void *p1, const void *p2)
{
return strcmp(*(const char **)p1, *(const char **)p2);
}
int config__get_dir_files(const char *include_dir, char ***files, int *file_count)
{
char **l_files = NULL;
@ -160,6 +166,7 @@ int config__get_dir_files(const char *include_dir, char ***files, int *file_coun
}
closedir(dh);
qsort(l_files, l_file_count, sizeof(char *), scmp_p);
*files = l_files;
*file_count = l_file_count;

View File

@ -104,7 +104,9 @@ void context__cleanup(struct mosquitto_db *db, struct mosquitto *context, bool d
{
struct mosquitto__packet *packet;
struct mosquitto_client_msg *msg, *next;
#ifdef WITH_BRIDGE
int i;
#endif
if(!context) return;
@ -164,14 +166,10 @@ void context__cleanup(struct mosquitto_db *db, struct mosquitto *context, bool d
assert(db); /* db can only be NULL here if the client hasn't sent a
CONNECT and hence wouldn't have an id. */
HASH_DELETE(hh_id, db->contexts_by_id, context);
context__remove_from_by_id(db, context);
mosquitto__free(context->id);
context->id = NULL;
}
if(context->old_id){
mosquitto__free(context->old_id);
context->old_id = NULL;
}
packet__cleanup(&(context->in_packet));
if(context->current_out_packet){
packet__cleanup(context->current_out_packet);
@ -281,3 +279,11 @@ void context__free_disused(struct mosquitto_db *db)
db->ll_for_free = NULL;
}
void context__remove_from_by_id(struct mosquitto_db *db, struct mosquitto *context)
{
if(context->removed_from_by_id == false && context->id){
HASH_DELETE(hh_id, db->contexts_by_id, context);
context->removed_from_by_id = true;
}
}

View File

@ -199,6 +199,7 @@ void db__msg_store_remove(struct mosquitto_db *db, struct mosquitto_msg_store *s
db->msg_store_bytes -= store->payloadlen;
mosquitto__free(store->source_id);
mosquitto__free(store->source_username);
if(store->dest_ids){
for(i=0; i<store->dest_id_count; i++){
mosquitto__free(store->dest_ids[i]);
@ -288,7 +289,7 @@ void db__message_dequeue_first(struct mosquitto *context)
msg->next = NULL;
}
int db__message_delete(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir)
int db__message_delete(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, enum mosquitto_msg_state expect_state, int qos)
{
struct mosquitto_client_msg *tail, *last = NULL;
int msg_index = 0;
@ -299,6 +300,11 @@ int db__message_delete(struct mosquitto_db *db, struct mosquitto *context, uint1
while(tail){
msg_index++;
if(tail->mid == mid && tail->direction == dir){
if(tail->qos != qos){
return MOSQ_ERR_PROTOCOL;
}else if(qos == 2 && tail->state != expect_state){
return MOSQ_ERR_PROTOCOL;
}
msg_index--;
db__message_remove(db, context, &tail, last);
}else{
@ -520,13 +526,16 @@ int db__message_insert(struct mosquitto_db *db, struct mosquitto *context, uint1
#endif
}
int db__message_update(struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, enum mosquitto_msg_state state)
int db__message_update(struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, enum mosquitto_msg_state state, int qos)
{
struct mosquitto_client_msg *tail;
tail = context->inflight_msgs;
while(tail){
if(tail->mid == mid && tail->direction == dir){
if(tail->qos != qos){
return MOSQ_ERR_PROTOCOL;
}
tail->state = state;
tail->timestamp = mosquitto_time();
return MOSQ_ERR_SUCCESS;
@ -604,13 +613,13 @@ int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context,
local_properties = *properties;
*properties = NULL;
}
if(db__message_store(db, source_id, 0, topic_heap, qos, payloadlen, &payload_uhpa, retain, &stored, message_expiry_interval, local_properties, 0)) return 1;
if(db__message_store(db, context, 0, topic_heap, qos, payloadlen, &payload_uhpa, retain, &stored, message_expiry_interval, local_properties, 0)) return 1;
return sub__messages_queue(db, source_id, topic_heap, qos, retain, &stored);
}
/* This function requires topic to be allocated on the heap. Once called, it owns topic and will free it on error. Likewise payload and properties. */
int db__message_store(struct mosquitto_db *db, const char *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, uint32_t message_expiry_interval, mosquitto_property *properties, dbid_t store_id)
int db__message_store(struct mosquitto_db *db, const struct mosquitto *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, uint32_t message_expiry_interval, mosquitto_property *properties, dbid_t store_id)
{
struct mosquitto_msg_store *temp = NULL;
int rc = MOSQ_ERR_SUCCESS;
@ -618,7 +627,7 @@ int db__message_store(struct mosquitto_db *db, const char *source, uint16_t sour
assert(db);
assert(stored);
temp = mosquitto__malloc(sizeof(struct mosquitto_msg_store));
temp = mosquitto__calloc(1, sizeof(struct mosquitto_msg_store));
if(!temp){
log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
rc = MOSQ_ERR_NOMEM;
@ -629,8 +638,8 @@ int db__message_store(struct mosquitto_db *db, const char *source, uint16_t sour
temp->payload.ptr = NULL;
temp->ref_count = 0;
if(source){
temp->source_id = mosquitto__strdup(source);
if(source && source->id){
temp->source_id = mosquitto__strdup(source->id);
}else{
temp->source_id = mosquitto__strdup("");
}
@ -639,6 +648,17 @@ int db__message_store(struct mosquitto_db *db, const char *source, uint16_t sour
rc = MOSQ_ERR_NOMEM;
goto error;
}
if(source && source->username){
temp->source_username = mosquitto__strdup(source->username);
if(!temp->source_username){
rc = MOSQ_ERR_NOMEM;
goto error;
}
}
if(source){
temp->source_listener = source->listener;
}
temp->source_mid = source_mid;
temp->mid = 0;
temp->qos = qos;
@ -677,6 +697,7 @@ error:
mosquitto__free(topic);
if(temp){
mosquitto__free(temp->source_id);
mosquitto__free(temp->source_username);
mosquitto__free(temp->topic);
mosquitto__free(temp);
}
@ -807,7 +828,6 @@ int db__message_reconnect_reset(struct mosquitto_db *db, struct mosquitto *conte
int db__message_release(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir)
{
struct mosquitto_client_msg *tail, *last = NULL;
int qos;
int retain;
char *topic;
char *source_id;
@ -820,7 +840,9 @@ int db__message_release(struct mosquitto_db *db, struct mosquitto *context, uint
while(tail){
msg_index++;
if(tail->mid == mid && tail->direction == dir){
qos = tail->store->qos;
if(tail->store->qos != 2){
return MOSQ_ERR_PROTOCOL;
}
topic = tail->store->topic;
retain = tail->retain;
source_id = tail->store->source_id;
@ -829,7 +851,7 @@ int db__message_release(struct mosquitto_db *db, struct mosquitto *context, uint
* denied/dropped and is being processed so the client doesn't
* keep resending it. That means we don't send it to other
* clients. */
if(!topic || !sub__messages_queue(db, source_id, topic, qos, retain, &tail->store)){
if(!topic || !sub__messages_queue(db, source_id, topic, 2, retain, &tail->store)){
db__message_remove(db, context, &tail, last);
deleted = true;
}else{

View File

@ -1,6 +1,6 @@
include ../../config.mk
CFLAGS_FINAL=${CFLAGS} -I.. -I../../lib -I../..
CFLAGS_FINAL=${CFLAGS} -I.. -I../../lib -I../.. -I../deps
.PHONY: all clean reallyclean

View File

@ -83,7 +83,9 @@ struct db_msg
uint8_t qos, retain;
uint8_t *payload;
char *source_id;
char *source_username;
char *topic;
uint16_t source_port;
};
static uint32_t db_version;
@ -177,6 +179,8 @@ print_db_msg(struct db_msg *msg, int length)
printf("\tLength: %d\n", length);
printf("\tStore ID: %" PRIu64 "\n", msg->store_id);
printf("\tSource ID: %s\n", msg->source_id);
printf("\tSource Username: %s\n", msg->source_username);
printf("\tSource Port: %d\n", msg->source_port);
printf("\tSource MID: %d\n", msg->source_mid);
printf("\tMID: %d\n", msg->mid);
printf("\tTopic: %s\n", msg->topic);
@ -194,26 +198,49 @@ print_db_msg(struct db_msg *msg, int length)
}
static int persist__read_string(FILE *db_fptr, char **str)
{
uint16_t i16temp;
uint16_t slen;
char *s = NULL;
if(fread(&i16temp, 1, sizeof(uint16_t), db_fptr) != sizeof(uint16_t)){
return MOSQ_ERR_INVAL;
}
slen = ntohs(i16temp);
if(slen){
s = mosquitto__malloc(slen+1);
if(!s){
fclose(db_fptr);
fprintf(stderr, "Error: Out of memory.\n");
return MOSQ_ERR_NOMEM;
}
if(fread(s, 1, slen, db_fptr) != slen){
mosquitto__free(s);
fprintf(stderr, "Error: %s.\n", strerror(errno));
return MOSQ_ERR_INVAL;
}
s[slen] = '\0';
}
*str = s;
return MOSQ_ERR_SUCCESS;
}
static int db__client_chunk_restore(struct mosquitto_db *db, FILE *db_fd, struct db_client *client)
{
uint16_t i16temp, slen;
uint16_t i16temp;
int rc = 0;
struct client_chunk *cc;
read_e(db_fd, &i16temp, sizeof(uint16_t));
slen = ntohs(i16temp);
if(!slen){
rc = persist__read_string(db_fd, &client->client_id);
if(rc){
fprintf(stderr, "Error: Corrupt persistent database.");
fclose(db_fd);
return 1;
return rc;
}
client->client_id = calloc(slen+1, sizeof(char));
if(!client->client_id){
fclose(db_fd);
fprintf(stderr, "Error: Out of memory.");
return 1;
}
read_e(db_fd, client->client_id, slen);
read_e(db_fd, &i16temp, sizeof(uint16_t));
client->last_mid = ntohs(i16temp);
@ -245,24 +272,17 @@ error:
static int db__client_msg_chunk_restore(struct mosquitto_db *db, FILE *db_fd, uint32_t length, struct db_client_msg *msg)
{
dbid_t i64temp;
uint16_t i16temp, slen;
uint16_t i16temp;
struct client_chunk *cc;
struct msg_store_chunk *msc;
int rc;
read_e(db_fd, &i16temp, sizeof(uint16_t));
slen = ntohs(i16temp);
if(!slen){
rc = persist__read_string(db_fd, &msg->client_id);
if(rc){
fprintf(stderr, "Error: Corrupt persistent database.");
fclose(db_fd);
return 1;
return rc;
}
msg->client_id = calloc(slen+1, sizeof(char));
if(!msg->client_id){
fclose(db_fd);
fprintf(stderr, "Error: Out of memory.");
return 1;
}
read_e(db_fd, msg->client_id, slen);
read_e(db_fd, &i64temp, sizeof(dbid_t));
msg->store_id = i64temp;
@ -301,58 +321,48 @@ static int db__msg_store_chunk_restore(struct mosquitto_db *db, FILE *db_fd, uin
{
dbid_t i64temp;
uint32_t i32temp;
uint16_t i16temp, slen;
uint16_t i16temp;
int rc = 0;
struct msg_store_chunk *mcs;
read_e(db_fd, &i64temp, sizeof(dbid_t));
msg->store_id = i64temp;
read_e(db_fd, &i16temp, sizeof(uint16_t));
slen = ntohs(i16temp);
if(slen){
msg->source_id = calloc(slen+1, sizeof(char));
if(!msg->source_id){
fclose(db_fd);
fprintf(stderr, "Error: Out of memory.");
return 1;
}
if(fread(msg->source_id, 1, slen, db_fd) != slen){
rc = persist__read_string(db_fd, &msg->source_id);
if(rc){
fprintf(stderr, "Error: Corrupt persistent database.");
fclose(db_fd);
return rc;
}
if(db_version == 4){
rc = persist__read_string(db_fd, &msg->source_username);
if(rc){
fprintf(stderr, "Error: %s.", strerror(errno));
fclose(db_fd);
free(msg->source_id);
free(msg->topic);
free(msg->payload);
free(msg->source_id);
return 1;
}
read_e(db_fd, &i16temp, sizeof(uint16_t));
msg->source_port = ntohs(i16temp);
}
read_e(db_fd, &i16temp, sizeof(uint16_t));
msg->source_mid = ntohs(i16temp);
read_e(db_fd, &i16temp, sizeof(uint16_t));
msg->mid = ntohs(i16temp);
read_e(db_fd, &i16temp, sizeof(uint16_t));
slen = ntohs(i16temp);
if(slen){
msg->topic = calloc(slen+1, sizeof(char));
if(!msg->topic){
fclose(db_fd);
free(msg->source_id);
fprintf(stderr, "Error: Out of memory.");
return 1;
}
if(fread(msg->topic, 1, slen, db_fd) != slen){
fprintf(stderr, "Error: %s.", strerror(errno));
fclose(db_fd);
free(msg->source_id);
free(msg->topic);
return 1;
}
}else{
fprintf(stderr, "Error: Invalid msg_store chunk when restoring persistent database.");
rc = persist__read_string(db_fd, &msg->topic);
if(rc){
fprintf(stderr, "Error: Corrupt persistent database.");
fclose(db_fd);
free(msg->source_id);
return 1;
return rc;
}
read_e(db_fd, &msg->qos, sizeof(uint8_t));
read_e(db_fd, &msg->retain, sizeof(uint8_t));
@ -415,29 +425,23 @@ static int db__retain_chunk_restore(struct mosquitto_db *db, FILE *db_fd)
static int db__sub_chunk_restore(struct mosquitto_db *db, FILE *db_fd, uint32_t length, struct db_sub *sub)
{
uint16_t i16temp, slen;
int rc = 0;
struct client_chunk *cc;
read_e(db_fd, &i16temp, sizeof(uint16_t));
slen = ntohs(i16temp);
sub->client_id = calloc(slen+1, sizeof(char));
if(!sub->client_id){
rc = persist__read_string(db_fd, &sub->client_id);
if(rc){
fprintf(stderr, "Error: Corrupt persistent database.");
fclose(db_fd);
fprintf(stderr, "Error: Out of memory.");
return 1;
return rc;
}
read_e(db_fd, sub->client_id, slen);
read_e(db_fd, &i16temp, sizeof(uint16_t));
slen = ntohs(i16temp);
sub->topic = calloc(slen+1, sizeof(char));
if(!sub->topic){
rc = persist__read_string(db_fd, &sub->topic);
if(rc){
fprintf(stderr, "Error: Corrupt persistent database.");
fclose(db_fd);
fprintf(stderr, "Error: Out of memory.");
free(sub->client_id);
return 1;
return rc;
}
read_e(db_fd, sub->topic, slen);
read_e(db_fd, &sub->qos, sizeof(uint8_t));
if(client_stats){

View File

@ -173,13 +173,11 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context)
uint8_t username_flag, password_flag;
char *username = NULL, *password = NULL;
int rc;
struct mosquitto__acl_user *acl_tail;
struct mosquitto *found_context;
int slen;
uint16_t slen16;
struct mosquitto__subleaf *leaf;
int i;
struct mosquitto__security_options *security_opts;
mosquitto_property *properties = NULL;
mosquitto_property *connack_props = NULL;
#ifdef WITH_TLS
@ -446,8 +444,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context)
rc = packet__read_string(&context->in_packet, &username, &slen);
if(rc == MOSQ_ERR_SUCCESS){
if(password_flag){
/* FIXME - MQTT 5 this is binary data */
rc = packet__read_string(&context->in_packet, &password, &slen);
rc = packet__read_binary(&context->in_packet, (uint8_t **)&password, &slen);
if(rc == MOSQ_ERR_NOMEM){
rc = MOSQ_ERR_NOMEM;
goto handle_connect_error;
@ -695,36 +692,8 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context)
do_disconnect(db, found_context);
}
/* Associate user with its ACL, assuming we have ACLs loaded. */
if(db->config->per_listener_settings){
if(!context->listener){
return 1;
}
security_opts = &context->listener->security_options;
}else{
security_opts = &db->config->security_options;
}
if(security_opts->acl_list){
acl_tail = security_opts->acl_list;
while(acl_tail){
if(context->username){
if(acl_tail->username && !strcmp(context->username, acl_tail->username)){
context->acl_list = acl_tail;
break;
}
}else{
if(acl_tail->username == NULL){
context->acl_list = acl_tail;
break;
}
}
acl_tail = acl_tail->next;
}
}else{
context->acl_list = NULL;
}
rc = acl__find_acls(db, context);
if(rc) return rc;
if(will_struct){
context->will = will_struct;

View File

@ -172,6 +172,11 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context)
}else if(topic == NULL && topic_alias == 0){
return MOSQ_ERR_PROTOCOL;
}
if(mosquitto_validate_utf8(topic, slen) != MOSQ_ERR_SUCCESS){
log__printf(NULL, MOSQ_LOG_INFO, "Client %s sent topic with invalid UTF-8, disconnecting.", context->id);
mosquitto__free(topic);
return 1;
}
#ifdef WITH_BRIDGE
if(context->bridge && context->bridge->topics && context->bridge->topic_remapping){
@ -280,7 +285,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context)
}
if(!stored){
dup = 0;
if(db__message_store(db, context->id, mid, topic, qos, payloadlen, &payload, retain, &stored, message_expiry_interval, msg_properties, 0)){
if(db__message_store(db, context, mid, topic, qos, payloadlen, &payload, retain, &stored, message_expiry_interval, msg_properties, 0)){
mosquitto_property_free_all(&msg_properties);
return 1;
}
@ -328,7 +333,7 @@ process_bad_message:
case 2:
db__message_store_find(context, mid, &stored);
if(!stored){
if(db__message_store(db, context->id, mid, NULL, qos, 0, NULL, false, &stored, 0, NULL, 0)){
if(db__message_store(db, context, mid, NULL, qos, 0, NULL, false, &stored, 0, NULL, 0)){
return 1;
}
res = db__message_insert(db, context, mid, mosq_md_in, qos, false, stored, NULL);

View File

@ -128,11 +128,11 @@ int mosquitto_main_loop(struct mosquitto_db *db, mosq_sock_t *listensock, int li
#endif
#ifdef WITH_BRIDGE
int rc;
int err;
socklen_t len;
#endif
time_t expiration_check_time = 0;
char *id;
int err;
socklen_t len;
#ifndef WIN32
sigemptyset(&sigblock);
@ -644,19 +644,13 @@ void do_disconnect(struct mosquitto_db *db, struct mosquitto *context)
context->sock = INVALID_SOCKET;
context->pollfd_index = -1;
}
if(context->id){
HASH_DELETE(hh_id, db->contexts_by_id, context);
context->old_id = context->id;
context->id = NULL;
}
context__remove_from_by_id(db, context);
}else
#endif
{
if(db->config->connection_messages == true){
if(context->id){
id = context->id;
}else if(context->old_id){
id = context->old_id;
}else{
id = "<unknown>";
}
@ -681,7 +675,7 @@ void do_disconnect(struct mosquitto_db *db, struct mosquitto *context)
#endif
context__add_to_disused(db, context);
if(context->id){
HASH_DELETE(hh_id, db->contexts_by_id, context);
context__remove_from_by_id(db, context);
mosquitto__free(context->id);
context->id = NULL;
}

View File

@ -249,6 +249,7 @@ struct mosquitto__config {
bool allow_duplicate_messages;
int autosave_interval;
bool autosave_on_changes;
bool check_retain_source;
char *clientid_prefixes;
bool connection_messages;
bool daemon;
@ -319,6 +320,8 @@ struct mosquitto_msg_store{
struct mosquitto_msg_store *prev;
dbid_t db_id;
char *source_id;
char *source_username;
struct mosquitto__listener *source_listener;
char **dest_ids;
int dest_id_count;
int ref_count;
@ -557,15 +560,15 @@ int persist__restore(struct mosquitto_db *db);
void db__limits_set(unsigned long inflight_bytes, int queued, unsigned long queued_bytes);
/* Return the number of in-flight messages in count. */
int db__message_count(int *count);
int db__message_delete(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir);
int db__message_delete(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, enum mosquitto_msg_state expect_state, int qos);
int db__message_insert(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, int qos, bool retain, struct mosquitto_msg_store *stored, mosquitto_property *properties);
int db__message_release(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir);
int db__message_update(struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, enum mosquitto_msg_state state);
int db__message_update(struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, enum mosquitto_msg_state state, int qos);
int db__message_write(struct mosquitto_db *db, struct mosquitto *context);
void db__message_dequeue_first(struct mosquitto *context);
int db__messages_delete(struct mosquitto_db *db, struct mosquitto *context);
int db__messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int qos, uint32_t payloadlen, const void *payload, int retain, uint32_t message_expiry_interval, mosquitto_property **properties);
int db__message_store(struct mosquitto_db *db, const char *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, uint32_t message_expiry_interval, mosquitto_property *properties, dbid_t store_id);
int db__message_store(struct mosquitto_db *db, const struct mosquitto *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, uint32_t message_expiry_interval, mosquitto_property *properties, dbid_t store_id);
int db__message_store_find(struct mosquitto *context, uint16_t mid, struct mosquitto_msg_store **stored);
void db__msg_store_add(struct mosquitto_db *db, struct mosquitto_msg_store *store);
void db__msg_store_remove(struct mosquitto_db *db, struct mosquitto_msg_store *store);
@ -596,6 +599,7 @@ void context__disconnect(struct mosquitto_db *db, struct mosquitto *context);
void context__add_to_disused(struct mosquitto_db *db, struct mosquitto *context);
void context__free_disused(struct mosquitto_db *db);
void context__send_will(struct mosquitto_db *db, struct mosquitto *context);
void context__remove_from_by_id(struct mosquitto_db *db, struct mosquitto *context);
/* ============================================================
* Logging functions
@ -625,6 +629,7 @@ int property__process_disconnect(struct mosquitto *context, mosquitto_property *
/* ============================================================
* Security related functions
* ============================================================ */
int acl__find_acls(struct mosquitto_db *db, struct mosquitto *context);
int mosquitto_security_module_init(struct mosquitto_db *db);
int mosquitto_security_module_cleanup(struct mosquitto_db *db);

View File

@ -387,7 +387,9 @@ int main(int argc, char *argv[])
signal(SIGINT, handle_sigint);
signal(SIGTERM, handle_sigint);
#if OPENSSL_VERSION_NUMBER < 0x10100000L || OPENSSL_API_COMPAT < 0x10100000L
OpenSSL_add_all_digests();
#endif
if(argc == 1){
print_usage();

View File

@ -39,6 +39,8 @@ static uint32_t db_version;
static int persist__restore_sub(struct mosquitto_db *db, const char *client_id, const char *sub, int qos);
static int persist__read_string(FILE *db_fptr, char **str);
static int persist__write_string(FILE *db_fptr, const char *str, bool nullok);
static struct mosquitto *persist__find_or_add_context(struct mosquitto_db *db, const char *client_id, uint16_t last_mid)
{
@ -139,7 +141,7 @@ static int persist__message_store_write(struct mosquitto_db *db, FILE *db_fptr)
uint32_t length;
dbid_t i64temp;
uint32_t i32temp;
uint16_t i16temp, slen, tlen;
uint16_t i16temp, tlen;
uint8_t i8temp;
struct mosquitto_msg_store *stored;
bool force_no_retain;
@ -168,10 +170,19 @@ static int persist__message_store_write(struct mosquitto_db *db, FILE *db_fptr)
}else{
tlen = 0;
}
length = htonl(sizeof(dbid_t) + 2+strlen(stored->source_id) +
length = sizeof(dbid_t) + 2+strlen(stored->source_id) +
sizeof(uint16_t) + sizeof(uint16_t) +
2+tlen + sizeof(uint32_t) +
stored->payloadlen + sizeof(uint8_t) + sizeof(uint8_t));
stored->payloadlen + sizeof(uint8_t) + sizeof(uint8_t)
+ 2*sizeof(uint16_t);
if(stored->source_id){
length += strlen(stored->source_id);
}
if(stored->source_username){
length += strlen(stored->source_username);
}
length = htonl(length);
i16temp = htons(DB_CHUNK_MSG_STORE);
write_e(db_fptr, &i16temp, sizeof(uint16_t));
@ -180,12 +191,15 @@ static int persist__message_store_write(struct mosquitto_db *db, FILE *db_fptr)
i64temp = stored->db_id;
write_e(db_fptr, &i64temp, sizeof(dbid_t));
slen = strlen(stored->source_id);
i16temp = htons(slen);
write_e(db_fptr, &i16temp, sizeof(uint16_t));
if(slen){
write_e(db_fptr, stored->source_id, slen);
if(persist__write_string(db_fptr, stored->source_id, false)) return 1;
if(persist__write_string(db_fptr, stored->source_username, true)) return 1;
if(stored->source_listener){
i16temp = htons(stored->source_listener->port);
}else{
i16temp = 0;
}
write_e(db_fptr, &i16temp, sizeof(uint16_t));
i16temp = htons(stored->source_mid);
write_e(db_fptr, &i16temp, sizeof(uint16_t));
@ -214,6 +228,7 @@ static int persist__message_store_write(struct mosquitto_db *db, FILE *db_fptr)
if(stored->payloadlen){
write_e(db_fptr, UHPA_ACCESS_PAYLOAD(stored), (unsigned int)stored->payloadlen);
}
stored = stored->next;
}
@ -265,6 +280,60 @@ error:
return 1;
}
static int persist__read_string(FILE *db_fptr, char **str)
{
uint16_t i16temp;
uint16_t slen;
char *s = NULL;
if(fread(&i16temp, 1, sizeof(uint16_t), db_fptr) != sizeof(uint16_t)){
return MOSQ_ERR_INVAL;
}
slen = ntohs(i16temp);
if(slen){
s = mosquitto__malloc(slen+1);
if(!s){
fclose(db_fptr);
log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
return MOSQ_ERR_NOMEM;
}
if(fread(s, 1, slen, db_fptr) != slen){
mosquitto__free(s);
return MOSQ_ERR_NOMEM;
}
s[slen] = '\0';
}
*str = s;
return MOSQ_ERR_SUCCESS;
}
static int persist__write_string(FILE *db_fptr, const char *str, bool nullok)
{
uint16_t i16temp, slen;
if(str){
slen = strlen(str);
i16temp = htons(slen);
write_e(db_fptr, &i16temp, sizeof(uint16_t));
write_e(db_fptr, str, slen);
}else if(nullok){
i16temp = htons(0);
write_e(db_fptr, &i16temp, sizeof(uint16_t));
}else{
return 1;
}
return MOSQ_ERR_SUCCESS;
error:
log__printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno));
return 1;
}
static int persist__subs_retain_write(struct mosquitto_db *db, FILE *db_fptr, struct mosquitto__subhier *node, const char *topic, int level)
{
struct mosquitto__subhier *subhier, *subhier_tmp;
@ -642,15 +711,16 @@ static int persist__msg_store_chunk_restore(struct mosquitto_db *db, FILE *db_fp
{
dbid_t i64temp, store_id;
uint32_t i32temp, payloadlen = 0;
uint16_t i16temp, slen, source_mid;
uint16_t i16temp, source_mid, source_port = 0;
uint8_t qos, retain;
mosquitto__payload_uhpa payload;
char *source_id = NULL;
struct mosquitto source;
char *topic = NULL;
int rc = 0;
struct mosquitto_msg_store *stored = NULL;
struct mosquitto_msg_store_load *load;
char *err;
int i;
payload.ptr = NULL;
@ -664,41 +734,45 @@ static int persist__msg_store_chunk_restore(struct mosquitto_db *db, FILE *db_fp
read_e(db_fptr, &i64temp, sizeof(dbid_t));
store_id = i64temp;
read_e(db_fptr, &i16temp, sizeof(uint16_t));
slen = ntohs(i16temp);
if(slen){
source_id = mosquitto__malloc(slen+1);
if(!source_id){
mosquitto__free(load);
fclose(db_fptr);
log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
return MOSQ_ERR_NOMEM;
}
read_e(db_fptr, source_id, slen);
source_id[slen] = '\0';
memset(&source, 0, sizeof(struct mosquitto));
rc = persist__read_string(db_fptr, &source.id);
if(rc){
mosquitto__free(load);
return rc;
}
if(db_version == 4){
rc = persist__read_string(db_fptr, &source.username);
if(rc){
mosquitto__free(load);
return rc;
}
read_e(db_fptr, &i16temp, sizeof(uint16_t));
source_port = ntohs(i16temp);
if(source_port){
for(i=0; i<db->config->listener_count; i++){
if(db->config->listeners[i].port == source_port){
source.listener = &db->config->listeners[i];
break;
}
}
}
}
read_e(db_fptr, &i16temp, sizeof(uint16_t));
source_mid = ntohs(i16temp);
/* This is the mid - don't need it */
read_e(db_fptr, &i16temp, sizeof(uint16_t));
read_e(db_fptr, &i16temp, sizeof(uint16_t));
slen = ntohs(i16temp);
if(slen){
topic = mosquitto__malloc(slen+1);
if(!topic){
mosquitto__free(load);
fclose(db_fptr);
mosquitto__free(source_id);
log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
return MOSQ_ERR_NOMEM;
}
read_e(db_fptr, topic, slen);
topic[slen] = '\0';
}else{
topic = NULL;
rc = persist__read_string(db_fptr, &topic);
if(rc){
mosquitto__free(load);
fclose(db_fptr);
mosquitto__free(source.id);
return rc;
}
read_e(db_fptr, &qos, sizeof(uint8_t));
read_e(db_fptr, &retain, sizeof(uint8_t));
@ -709,7 +783,7 @@ static int persist__msg_store_chunk_restore(struct mosquitto_db *db, FILE *db_fp
if(UHPA_ALLOC(payload, payloadlen) == 0){
mosquitto__free(load);
fclose(db_fptr);
mosquitto__free(source_id);
mosquitto__free(source.id);
mosquitto__free(topic);
log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
return MOSQ_ERR_NOMEM;
@ -717,8 +791,8 @@ static int persist__msg_store_chunk_restore(struct mosquitto_db *db, FILE *db_fp
read_e(db_fptr, UHPA_ACCESS(payload, payloadlen), payloadlen);
}
rc = db__message_store(db, source_id, source_mid, topic, qos, payloadlen, &payload, retain, &stored, 0, NULL, store_id);
mosquitto__free(source_id);
rc = db__message_store(db, &source, source_mid, topic, qos, payloadlen, &payload, retain, &stored, 0, NULL, store_id);
mosquitto__free(source.id);
if(rc == MOSQ_ERR_SUCCESS){
load->db_id = stored->db_id;
@ -737,7 +811,7 @@ error:
err = strerror(errno);
log__printf(NULL, MOSQ_LOG_ERR, "Error: %s.", err);
fclose(db_fptr);
mosquitto__free(source_id);
mosquitto__free(source.id);
mosquitto__free(topic);
UHPA_FREE(payload, payloadlen);
return 1;
@ -768,35 +842,24 @@ static int persist__retain_chunk_restore(struct mosquitto_db *db, FILE *db_fptr)
static int persist__sub_chunk_restore(struct mosquitto_db *db, FILE *db_fptr)
{
uint16_t i16temp, slen;
uint8_t qos;
char *client_id;
char *topic;
int rc = 0;
char *err;
read_e(db_fptr, &i16temp, sizeof(uint16_t));
slen = ntohs(i16temp);
client_id = mosquitto__malloc(slen+1);
if(!client_id){
rc = persist__read_string(db_fptr, &client_id);
if(rc){
fclose(db_fptr);
log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
return MOSQ_ERR_NOMEM;
return rc;
}
read_e(db_fptr, client_id, slen);
client_id[slen] = '\0';
read_e(db_fptr, &i16temp, sizeof(uint16_t));
slen = ntohs(i16temp);
topic = mosquitto__malloc(slen+1);
if(!topic){
fclose(db_fptr);
log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
rc = persist__read_string(db_fptr, &topic);
if(rc){
mosquitto__free(client_id);
return MOSQ_ERR_NOMEM;
fclose(db_fptr);
return rc;
}
read_e(db_fptr, topic, slen);
topic[slen] = '\0';
read_e(db_fptr, &qos, sizeof(uint8_t));
if(persist__restore_sub(db, client_id, topic, qos) > 0){
@ -852,7 +915,9 @@ int persist__restore(struct mosquitto_db *db)
* Is your DB change still compatible with previous versions?
*/
if(db_version > MOSQ_DB_VERSION && db_version != 0){
if(db_version == 2){
if(db_version == 3){
/* Addition of source_username and source_port to msg_store chunk in v4, v1.5.6 */
}else if(db_version == 2){
/* Addition of disconnect_t to client chunk in v3. */
}else{
fclose(fptr);

View File

@ -17,7 +17,7 @@ Contributors:
#ifndef PERSIST_H
#define PERSIST_H
#define MOSQ_DB_VERSION 3
#define MOSQ_DB_VERSION 4
/* DB read/write */
const unsigned char magic[15] = {0x00, 0xB5, 0x00, 'm','o','s','q','u','i','t','t','o',' ','d','b'};

View File

@ -317,7 +317,7 @@ int mosquitto_acl_check_default(struct mosquitto_db *db, struct mosquitto *conte
}else{
security_opts = &db->config->security_options;
}
if(!security_opts->acl_list && !security_opts->acl_patterns){
if(!security_opts->acl_file && !security_opts->acl_list && !security_opts->acl_patterns){
return MOSQ_ERR_PLUGIN_DEFER;
}
@ -535,6 +535,10 @@ static int aclfile__parse(struct mosquitto_db *db, struct mosquitto__security_op
fclose(aclfptr);
return 1;
}
}else{
log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid line in acl_file \"%s\": %s.", security_opts->acl_file, buf);
fclose(aclfptr);
return 1;
}
}
}
@ -606,6 +610,49 @@ static int acl__cleanup(struct mosquitto_db *db, bool reload)
return MOSQ_ERR_SUCCESS;
}
int acl__find_acls(struct mosquitto_db *db, struct mosquitto *context)
{
struct mosquitto__acl_user *acl_tail;
struct mosquitto__security_options *security_opts;
/* Associate user with its ACL, assuming we have ACLs loaded. */
if(db->config->per_listener_settings){
if(!context->listener){
return MOSQ_ERR_INVAL;
}
security_opts = &context->listener->security_options;
}else{
security_opts = &db->config->security_options;
}
if(security_opts->acl_list){
acl_tail = security_opts->acl_list;
while(acl_tail){
if(context->username){
if(acl_tail->username && !strcmp(context->username, acl_tail->username)){
context->acl_list = acl_tail;
break;
}
}else{
if(acl_tail->username == NULL){
context->acl_list = acl_tail;
break;
}
}
acl_tail = acl_tail->next;
}
if(context->username && context->acl_list == NULL){
return MOSQ_ERR_INVAL;
}
}else{
context->acl_list = NULL;
}
return MOSQ_ERR_SUCCESS;
}
static int pwfile__parse(const char *file, struct mosquitto__unpwd **root)
{
FILE *pwfile;
@ -623,6 +670,9 @@ static int pwfile__parse(const char *file, struct mosquitto__unpwd **root)
while(!feof(pwfile)){
if(fgets(buf, 256, pwfile)){
if(buf[0] == '#') continue;
if(!strchr(buf, ':')) continue;
username = strtok_r(buf, ":", &saveptr);
if(username){
unpwd = mosquitto__calloc(1, sizeof(struct mosquitto__unpwd));
@ -655,8 +705,13 @@ static int pwfile__parse(const char *file, struct mosquitto__unpwd **root)
unpwd->password[len-1] = '\0';
len = strlen(unpwd->password);
}
HASH_ADD_KEYPTR(hh, *root, unpwd->username, strlen(unpwd->username), unpwd);
}else{
log__printf(NULL, MOSQ_LOG_NOTICE, "Warning: Invalid line in password file '%s': %s", file, buf);
mosquitto__free(unpwd->username);
mosquitto__free(unpwd);
}
HASH_ADD_KEYPTR(hh, *root, unpwd->username, strlen(unpwd->username), unpwd);
}
}
}
@ -693,34 +748,39 @@ static int unpwd__file_parse(struct mosquitto__unpwd **unpwd, const char *passwo
token = strtok(NULL, "$");
if(token){
rc = base64__decode(token, &salt, &salt_len);
if(rc){
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to decode password salt for user %s.", u->username);
return MOSQ_ERR_INVAL;
}
u->salt = salt;
u->salt_len = salt_len;
token = strtok(NULL, "$");
if(token){
rc = base64__decode(token, &password, &password_len);
if(rc){
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to decode password for user %s.", u->username);
return MOSQ_ERR_INVAL;
if(rc == MOSQ_ERR_SUCCESS && salt_len == 12){
u->salt = salt;
u->salt_len = salt_len;
token = strtok(NULL, "$");
if(token){
rc = base64__decode(token, &password, &password_len);
if(rc == MOSQ_ERR_SUCCESS && password_len == 64){
mosquitto__free(u->password);
u->password = (char *)password;
u->password_len = password_len;
}else{
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to decode password for user %s, removing entry.", u->username);
HASH_DEL(*unpwd, u);
}
}else{
log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s, removing entry.", u->username);
HASH_DEL(*unpwd, u);
}
mosquitto__free(u->password);
u->password = (char *)password;
u->password_len = password_len;
}else{
log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s.", u->username);
return MOSQ_ERR_INVAL;
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to decode password salt for user %s, removing entry.", u->username);
HASH_DEL(*unpwd, u);
}
}else{
log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s.", u->username);
return MOSQ_ERR_INVAL;
log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s, removing entry.", u->username);
HASH_DEL(*unpwd, u);
}
}else{
log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s.", u->username);
return MOSQ_ERR_INVAL;
log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s, removing entry.", u->username);
HASH_DEL(*unpwd, u);
}
}else{
log__printf(NULL, MOSQ_LOG_ERR, "Error: Missing password hash for user %s, removing entry.", u->username);
HASH_DEL(*unpwd, u);
}
}
#endif
@ -794,7 +854,12 @@ int mosquitto_unpwd_check_default(struct mosquitto_db *db, struct mosquitto *con
if(!db->unpwd) return MOSQ_ERR_PLUGIN_DEFER;
unpwd_ref = db->unpwd;
}
if(!username) return MOSQ_ERR_INVAL; /* Check must be made only after checking unpwd_ref. */
if(!username){
/* Check must be made only after checking unpwd_ref.
* This is DENY here, because in MQTT v5 username can be missing when
* password is present, but we don't support that. */
return MOSQ_ERR_AUTH;
}
HASH_ITER(hh, unpwd_ref, u, tmp){
if(!strcmp(u->username, username)){

View File

@ -673,6 +673,27 @@ static int retain__process(struct mosquitto_db *db, struct mosquitto__subhier *b
return rc;
}
/* Check for original source access */
if(db->config->check_retain_source && retained->source_id){
struct mosquitto retain_ctxt;
memset(&retain_ctxt, 0, sizeof(struct mosquitto));
retain_ctxt.id = retained->source_id;
retain_ctxt.username = retained->source_username;
retain_ctxt.listener = retained->source_listener;
rc = acl__find_acls(db, &retain_ctxt);
if(rc) return rc;
rc = mosquitto_acl_check(db, &retain_ctxt, retained->topic, retained->payloadlen, UHPA_ACCESS(retained->payload, retained->payloadlen),
retained->qos, retained->retain, MOSQ_ACL_WRITE);
if(rc == MOSQ_ERR_ACL_DENIED){
return MOSQ_ERR_SUCCESS;
}else if(rc != MOSQ_ERR_SUCCESS){
return rc;
}
}
if (db->config->upgrade_outgoing_qos){
qos = sub_qos;
} else {

View File

@ -41,6 +41,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/stat.h>
extern struct mosquitto_db int_db;
@ -246,7 +247,7 @@ static int callback_mqtt(struct libwebsocket_context *context,
}
mosq = u->mosq;
if(mosq){
if(mosq->sock > 0){
if(mosq->sock != INVALID_SOCKET){
HASH_DELETE(hh_sock, db->contexts_by_sock, mosq);
mosq->sock = INVALID_SOCKET;
mosq->pollfd_index = -1;

View File

@ -0,0 +1,69 @@
#!/usr/bin/env python
# Test what the broker does if receiving a PUBCOMP in response to a QoS 1 PUBLISH.
import inspect, os, sys
# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder
cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"..")))
if cmd_subfolder not in sys.path:
sys.path.insert(0, cmd_subfolder)
import mosq_test
import time
rc = 1
keepalive = 60
connect_packet = mosq_test.gen_connect("subpub-qos1-test", keepalive=keepalive)
connack_packet = mosq_test.gen_connack(rc=0)
mid = 1
subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos1", 1)
suback_packet = mosq_test.gen_suback(mid, 1)
mid = 1
publish_packet2 = mosq_test.gen_publish("subpub/qos1", qos=1, mid=mid, payload="message")
helper_connect = mosq_test.gen_connect("helper", keepalive=keepalive)
helper_connack = mosq_test.gen_connack(rc=0)
mid = 1
publish1s_packet = mosq_test.gen_publish("subpub/qos1", qos=1, mid=mid, payload="message")
puback1s_packet = mosq_test.gen_puback(mid)
mid = 1
publish1r_packet = mosq_test.gen_publish("subpub/qos1", qos=1, mid=mid, payload="message")
pubcomp1r_packet = mosq_test.gen_pubcomp(mid)
pingreq_packet = mosq_test.gen_pingreq()
pingresp_packet = mosq_test.gen_pingresp()
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, timeout=20, port=port)
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback")
helper = mosq_test.do_client_connect(helper_connect, helper_connack, timeout=20, port=port)
mosq_test.do_send_receive(helper, publish1s_packet, puback1s_packet, "puback 1s")
helper.close()
if mosq_test.expect_packet(sock, "publish 1r", publish1r_packet):
sock.send(pubcomp1r_packet)
sock.send(pingreq_packet)
p = sock.recv(len(pingresp_packet))
if len(p) == 0:
rc = 0
sock.close()
finally:
broker.terminate()
broker.wait()
(stdo, stde) = broker.communicate()
if rc:
print(stde)
exit(rc)

View File

@ -0,0 +1,65 @@
#!/usr/bin/env python
# Test what the broker does if receiving a PUBREC in response to a QoS 1 PUBLISH.
import inspect, os, sys
# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder
cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"..")))
if cmd_subfolder not in sys.path:
sys.path.insert(0, cmd_subfolder)
import mosq_test
import time
rc = 1
keepalive = 60
connect_packet = mosq_test.gen_connect("subpub-qos1-test", keepalive=keepalive)
connack_packet = mosq_test.gen_connack(rc=0)
mid = 1
subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos1", 1)
suback_packet = mosq_test.gen_suback(mid, 1)
helper_connect = mosq_test.gen_connect("helper", keepalive=keepalive)
helper_connack = mosq_test.gen_connack(rc=0)
mid = 1
publish1s_packet = mosq_test.gen_publish("subpub/qos1", qos=1, mid=mid, payload="message")
puback1s_packet = mosq_test.gen_puback(mid)
mid = 1
publish1r_packet = mosq_test.gen_publish("subpub/qos1", qos=1, mid=mid, payload="message")
pubrec1r_packet = mosq_test.gen_pubrec(mid)
pingreq_packet = mosq_test.gen_pingreq()
pingresp_packet = mosq_test.gen_pingresp()
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, timeout=20, port=port)
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback")
helper = mosq_test.do_client_connect(helper_connect, helper_connack, timeout=20, port=port)
mosq_test.do_send_receive(helper, publish1s_packet, puback1s_packet, "puback 1s")
helper.close()
if mosq_test.expect_packet(sock, "publish 1r", publish1r_packet):
sock.send(pubrec1r_packet)
sock.send(pingreq_packet)
p = sock.recv(len(pingresp_packet))
if len(p) == 0:
rc = 0
sock.close()
finally:
broker.terminate()
broker.wait()
(stdo, stde) = broker.communicate()
if rc:
print(stde)
exit(rc)

View File

@ -0,0 +1,68 @@
#!/usr/bin/env python
# Test what the broker does if receiving a PUBACK in response to a QoS 2 PUBLISH.
import inspect, os, sys
# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder
cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"..")))
if cmd_subfolder not in sys.path:
sys.path.insert(0, cmd_subfolder)
import mosq_test
import time
rc = 1
keepalive = 60
connect_packet = mosq_test.gen_connect("subpub-qos2-test", keepalive=keepalive)
connack_packet = mosq_test.gen_connack(rc=0)
mid = 1
subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos2", 2)
suback_packet = mosq_test.gen_suback(mid, 2)
helper_connect = mosq_test.gen_connect("helper", keepalive=keepalive)
helper_connack = mosq_test.gen_connack(rc=0)
mid = 1
publish1s_packet = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message")
pubrec1s_packet = mosq_test.gen_pubrec(mid)
pubrel1s_packet = mosq_test.gen_pubrel(mid)
pubcomp1s_packet = mosq_test.gen_pubcomp(mid)
mid = 1
publish1r_packet = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message")
puback1r_packet = mosq_test.gen_puback(mid)
pingreq_packet = mosq_test.gen_pingreq()
pingresp_packet = mosq_test.gen_pingresp()
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, timeout=20, port=port)
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback")
helper = mosq_test.do_client_connect(helper_connect, helper_connack, timeout=20, port=port)
mosq_test.do_send_receive(helper, publish1s_packet, pubrec1s_packet, "pubrec 1s")
mosq_test.do_send_receive(helper, pubrel1s_packet, pubcomp1s_packet, "pubcomp 1s")
helper.close()
if mosq_test.expect_packet(sock, "publish 1r", publish1r_packet):
sock.send(puback1r_packet)
sock.send(pingreq_packet)
p = sock.recv(len(pingresp_packet))
if len(p) == 0:
rc = 0
sock.close()
finally:
broker.terminate()
broker.wait()
(stdo, stde) = broker.communicate()
if rc:
print(stde)
exit(rc)

View File

@ -0,0 +1,71 @@
#!/usr/bin/env python
# Test what the broker does if receiving a PUBACK in response to a QoS 2 PUBREL.
import inspect, os, sys
# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder
cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"..")))
if cmd_subfolder not in sys.path:
sys.path.insert(0, cmd_subfolder)
import mosq_test
import time
rc = 1
keepalive = 60
connect_packet = mosq_test.gen_connect("subpub-qos2-test", keepalive=keepalive)
connack_packet = mosq_test.gen_connack(rc=0)
mid = 1
subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos2", 2)
suback_packet = mosq_test.gen_suback(mid, 2)
helper_connect = mosq_test.gen_connect("helper", keepalive=keepalive)
helper_connack = mosq_test.gen_connack(rc=0)
mid = 1
publish1s_packet = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message")
pubrec1s_packet = mosq_test.gen_pubrec(mid)
pubrel1s_packet = mosq_test.gen_pubrel(mid)
pubcomp1s_packet = mosq_test.gen_pubcomp(mid)
mid = 1
publish1r_packet = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message")
pubrec1r_packet = mosq_test.gen_pubrec(mid)
pubrel1r_packet = mosq_test.gen_pubrel(mid)
puback1r_packet = mosq_test.gen_puback(mid)
pingreq_packet = mosq_test.gen_pingreq()
pingresp_packet = mosq_test.gen_pingresp()
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, timeout=20, port=port)
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback")
helper = mosq_test.do_client_connect(helper_connect, helper_connack, timeout=20, port=port)
mosq_test.do_send_receive(helper, publish1s_packet, pubrec1s_packet, "pubrec 1s")
mosq_test.do_send_receive(helper, pubrel1s_packet, pubcomp1s_packet, "pubcomp 1s")
helper.close()
if mosq_test.expect_packet(sock, "publish 1r", publish1r_packet):
mosq_test.do_send_receive(sock, pubrec1s_packet, pubrel1s_packet, "pubrel 1r")
sock.send(puback1r_packet)
sock.send(pingreq_packet)
p = sock.recv(len(pingresp_packet))
if len(p) == 0:
rc = 0
sock.close()
finally:
broker.terminate()
broker.wait()
(stdo, stde) = broker.communicate()
if rc:
print(stde)
exit(rc)

View File

@ -0,0 +1,68 @@
#!/usr/bin/env python
# Test what the broker does if receiving a PUBCOMP in response to a QoS 2 PUBLISH.
import inspect, os, sys
# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder
cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"..")))
if cmd_subfolder not in sys.path:
sys.path.insert(0, cmd_subfolder)
import mosq_test
import time
rc = 1
keepalive = 60
connect_packet = mosq_test.gen_connect("subpub-qos2-test", keepalive=keepalive)
connack_packet = mosq_test.gen_connack(rc=0)
mid = 1
subscribe_packet = mosq_test.gen_subscribe(mid, "subpub/qos2", 2)
suback_packet = mosq_test.gen_suback(mid, 2)
helper_connect = mosq_test.gen_connect("helper", keepalive=keepalive)
helper_connack = mosq_test.gen_connack(rc=0)
mid = 1
publish1s_packet = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message")
pubrec1s_packet = mosq_test.gen_pubrec(mid)
pubrel1s_packet = mosq_test.gen_pubrel(mid)
pubcomp1s_packet = mosq_test.gen_pubcomp(mid)
mid = 1
publish1r_packet = mosq_test.gen_publish("subpub/qos2", qos=2, mid=mid, payload="message")
pubcomp1r_packet = mosq_test.gen_pubcomp(mid)
pingreq_packet = mosq_test.gen_pingreq()
pingresp_packet = mosq_test.gen_pingresp()
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, timeout=20, port=port)
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback")
helper = mosq_test.do_client_connect(helper_connect, helper_connack, timeout=20, port=port)
mosq_test.do_send_receive(helper, publish1s_packet, pubrec1s_packet, "pubrec 1s")
mosq_test.do_send_receive(helper, pubrel1s_packet, pubcomp1s_packet, "pubcomp 1s")
helper.close()
if mosq_test.expect_packet(sock, "publish 1r", publish1r_packet):
sock.send(pubcomp1r_packet)
sock.send(pingreq_packet)
p = sock.recv(len(pingresp_packet))
if len(p) == 0:
rc = 0
sock.close()
finally:
broker.terminate()
broker.wait()
(stdo, stde) = broker.communicate()
if rc:
print(stde)
exit(rc)

View File

@ -0,0 +1,117 @@
#!/usr/bin/env python
# Test for CVE-2018-12546, with the broker being stopped to write the persistence file, plus subscriber on different port.
import inspect, os, sys
# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder
cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"..")))
if cmd_subfolder not in sys.path:
sys.path.insert(0, cmd_subfolder)
import mosq_test
import signal
def write_config(filename, port1, port2, per_listener):
with open(filename, 'w') as f:
f.write("per_listener_settings %s\n" % (per_listener))
f.write("check_retain_source true\n")
f.write("port %d\n" % (port1))
f.write("acl_file %s\n" % (filename.replace('.conf', '.acl')))
f.write("persistence true\n")
f.write("persistence_file %s\n" % (filename.replace('.conf', '.db')))
f.write("listener %d\n" % (port2))
def write_acl_1(filename, username):
with open(filename, 'w') as f:
if username is not None:
f.write('user %s\n' % (username))
f.write('topic readwrite test/topic\n')
def write_acl_2(filename, username):
with open(filename, 'w') as f:
if username is not None:
f.write('user %s\n' % (username))
f.write('topic read test/topic\n')
def do_test(per_listener, username):
conf_file = os.path.basename(__file__).replace('.py', '.conf')
write_config(conf_file, port1, port2, per_listener)
persistence_file = os.path.basename(__file__).replace('.py', '.db')
try:
os.remove(persistence_file)
except OSError:
pass
acl_file = os.path.basename(__file__).replace('.py', '.acl')
write_acl_1(acl_file, username)
rc = 1
keepalive = 60
connect_packet = mosq_test.gen_connect("retain-check", keepalive=keepalive, username=username)
connack_packet = mosq_test.gen_connack(rc=0)
if per_listener == "true":
u = None
else:
# If per listener is false, then the second client will be denied
# unless we provide a username
u = username
connect2_packet = mosq_test.gen_connect("retain-recv", keepalive=keepalive, username=u)
connack2_packet = mosq_test.gen_connack(rc=0)
mid = 1
publish_packet = mosq_test.gen_publish("test/topic", qos=0, payload="retained message", retain=True)
subscribe_packet = mosq_test.gen_subscribe(mid, "test/topic", 0)
suback_packet = mosq_test.gen_suback(mid, 0)
pingreq_packet = mosq_test.gen_pingreq()
pingresp_packet = mosq_test.gen_pingresp()
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port1)
try:
sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port1)
sock.send(publish_packet)
sock.close()
sock = mosq_test.do_client_connect(connect2_packet, connack2_packet, port=port2)
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback 1")
if mosq_test.expect_packet(sock, "publish", publish_packet):
sock.close()
# Remove "write" ability
write_acl_2(acl_file, username)
broker.terminate()
broker.wait()
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port1)
sock = mosq_test.do_client_connect(connect2_packet, connack2_packet, port=port2)
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback 2")
# If we receive the retained message here, it is a failure.
mosq_test.do_send_receive(sock, pingreq_packet, pingresp_packet, "pingresp")
rc = 0
sock.close()
finally:
broker.terminate()
broker.wait()
os.remove(conf_file)
os.remove(acl_file)
os.remove(persistence_file)
(stdo, stde) = broker.communicate()
if rc:
print(stde)
exit(rc)
(port1, port2) = mosq_test.get_port(2)
do_test("true", username=None)
do_test("true", username="test")
do_test("false", username=None)
do_test("false", username="test")

View File

@ -0,0 +1,106 @@
#!/usr/bin/env python
# Test for CVE-2018-12546, with the broker being stopped to write the persistence file.
import inspect, os, sys
# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder
cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"..")))
if cmd_subfolder not in sys.path:
sys.path.insert(0, cmd_subfolder)
import mosq_test
import signal
def write_config(filename, port, per_listener):
with open(filename, 'w') as f:
f.write("per_listener_settings %s\n" % (per_listener))
f.write("check_retain_source true\n")
f.write("port %d\n" % (port))
f.write("acl_file %s\n" % (filename.replace('.conf', '.acl')))
f.write("persistence true\n")
f.write("persistence_file %s\n" % (filename.replace('.conf', '.db')))
def write_acl_1(filename, username):
with open(filename, 'w') as f:
if username is not None:
f.write('user %s\n' % (username))
f.write('topic readwrite test/topic\n')
def write_acl_2(filename, username):
with open(filename, 'w') as f:
if username is not None:
f.write('user %s\n' % (username))
f.write('topic read test/topic\n')
def do_test(per_listener, username):
conf_file = os.path.basename(__file__).replace('.py', '.conf')
write_config(conf_file, port, per_listener)
persistence_file = os.path.basename(__file__).replace('.py', '.db')
try:
os.remove(persistence_file)
except OSError:
pass
acl_file = os.path.basename(__file__).replace('.py', '.acl')
write_acl_1(acl_file, username)
rc = 1
keepalive = 60
connect_packet = mosq_test.gen_connect("retain-check", keepalive=keepalive, username=username)
connack_packet = mosq_test.gen_connack(rc=0)
mid = 1
publish_packet = mosq_test.gen_publish("test/topic", qos=0, payload="retained message", retain=True)
subscribe_packet = mosq_test.gen_subscribe(mid, "test/topic", 0)
suback_packet = mosq_test.gen_suback(mid, 0)
pingreq_packet = mosq_test.gen_pingreq()
pingresp_packet = mosq_test.gen_pingresp()
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
try:
sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port)
sock.send(publish_packet)
sock.close()
sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port)
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback 1")
if mosq_test.expect_packet(sock, "publish", publish_packet):
sock.close()
# Remove "write" ability
write_acl_2(acl_file, username)
broker.terminate()
broker.wait()
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port)
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback 2")
# If we receive the retained message here, it is a failure.
mosq_test.do_send_receive(sock, pingreq_packet, pingresp_packet, "pingresp")
rc = 0
sock.close()
finally:
broker.terminate()
broker.wait()
os.remove(conf_file)
os.remove(acl_file)
os.remove(persistence_file)
(stdo, stde) = broker.communicate()
if rc:
print(stde)
exit(rc)
port = mosq_test.get_port()
do_test("true", username=None)
do_test("true", username="test")
do_test("false", username=None)
do_test("false", username="test")

View File

@ -0,0 +1,87 @@
#!/usr/bin/env python
# Test for CVE-2018-12546
import inspect, os, sys
# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder
cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"..")))
if cmd_subfolder not in sys.path:
sys.path.insert(0, cmd_subfolder)
import mosq_test
import signal
def write_config(filename, port, per_listener):
with open(filename, 'w') as f:
f.write("per_listener_settings %s\n" % (per_listener))
f.write("check_retain_source true\n")
f.write("port %d\n" % (port))
f.write("acl_file %s\n" % (filename.replace('.conf', '.acl')))
def write_acl_1(filename):
with open(filename, 'w') as f:
f.write('topic readwrite test/topic\n')
def write_acl_2(filename):
with open(filename, 'w') as f:
f.write('topic read test/topic\n')
def do_test(per_listener):
conf_file = os.path.basename(__file__).replace('.py', '.conf')
write_config(conf_file, port, per_listener)
acl_file = os.path.basename(__file__).replace('.py', '.acl')
write_acl_1(acl_file)
rc = 1
keepalive = 60
connect_packet = mosq_test.gen_connect("retain-check", keepalive=keepalive)
connack_packet = mosq_test.gen_connack(rc=0)
mid = 1
publish_packet = mosq_test.gen_publish("test/topic", qos=0, payload="retained message", retain=True)
subscribe_packet = mosq_test.gen_subscribe(mid, "test/topic", 0)
suback_packet = mosq_test.gen_suback(mid, 0)
pingreq_packet = mosq_test.gen_pingreq()
pingresp_packet = mosq_test.gen_pingresp()
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
try:
sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port)
sock.send(publish_packet)
sock.close()
sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port)
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback 1")
if mosq_test.expect_packet(sock, "publish", publish_packet):
sock.close()
# Remove "write" ability
write_acl_2(acl_file)
broker.send_signal(signal.SIGHUP)
sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port)
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback 2")
# If we receive the retained message here, it is a failure.
mosq_test.do_send_receive(sock, pingreq_packet, pingresp_packet, "pingresp")
rc = 0
sock.close()
finally:
os.remove(conf_file)
os.remove(acl_file)
broker.terminate()
broker.wait()
(stdo, stde) = broker.communicate()
if rc:
print(stde)
exit(rc)
port = mosq_test.get_port()
do_test("true")
do_test("false")

View File

@ -0,0 +1,71 @@
#!/usr/bin/env python
# Test for CVE-2018-xxxxx
import inspect, os, sys
# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder
cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"..")))
if cmd_subfolder not in sys.path:
sys.path.insert(0, cmd_subfolder)
import mosq_test
import signal
def write_config(filename, port, per_listener):
with open(filename, 'w') as f:
f.write("per_listener_settings %s\n" % (per_listener))
f.write("port %d\n" % (port))
f.write("acl_file %s\n" % (filename.replace('.conf', '.acl')))
def write_acl(filename):
with open(filename, 'w') as f:
f.write('#comment\n')
f.write('\n')
def do_test(port, per_listener):
conf_file = os.path.basename(__file__).replace('.py', '.conf')
write_config(conf_file, port, per_listener)
acl_file = os.path.basename(__file__).replace('.py', '.acl')
write_acl(acl_file)
rc = 1
keepalive = 60
connect_packet = mosq_test.gen_connect("acl-check", keepalive=keepalive)
connack_packet = mosq_test.gen_connack(rc=0)
mid = 1
publish_packet = mosq_test.gen_publish("test/topic", qos=0, payload="message")
subscribe_packet = mosq_test.gen_subscribe(mid, "test/topic", 0)
suback_packet = mosq_test.gen_suback(mid, 0)
pingreq_packet = mosq_test.gen_pingreq()
pingresp_packet = mosq_test.gen_pingresp()
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
try:
sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port)
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback")
sock.send(publish_packet)
# If we receive the message, this will fail.
mosq_test.do_send_receive(sock, pingreq_packet, pingresp_packet, "pingresp")
rc = 0
sock.close()
finally:
os.remove(conf_file)
os.remove(acl_file)
broker.terminate()
broker.wait()
(stdo, stde) = broker.communicate()
if rc:
print(stde)
exit(rc)
port = mosq_test.get_port()
do_test(port, "false")
do_test(port, "true")

View File

@ -0,0 +1,169 @@
#!/usr/bin/env python
# Test for CVE-2018-xxxxx.
import inspect, os, sys
# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder
cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"..")))
if cmd_subfolder not in sys.path:
sys.path.insert(0, cmd_subfolder)
import mosq_test
import signal
def write_config(filename, port, per_listener):
with open(filename, 'w') as f:
f.write("per_listener_settings %s\n" % (per_listener))
f.write("port %d\n" % (port))
f.write("password_file %s\n" % (filename.replace('.conf', '.pwfile')))
f.write("allow_anonymous false")
def write_pwfile(filename, bad_line1, bad_line2):
with open(filename, 'w') as f:
if bad_line1 is not None:
f.write('%s\n' % (bad_line1))
# Username test, password test
f.write('test:$6$njERlZMi/7DzNB9E$iiavfuXvUm8iyDZArTy7smTxh07GXXOrOsqxfW6gkOYVXHGk+W+i/8d3xDxrMwEPygEBhoA8A/gjQC0N2M4Lkw==\n')
# Username empty, password 0 length
f.write('empty:$6$o+53eGXtmlfHeYrg$FY7X9DNQ4uU1j0NiPmGOOSU05ZSzhqNmNhXIof/0nLpVb1zDhcRHdaC72E3YryH7dtTiG/r6jH6C8J+30cZBgA==\n')
if bad_line2 is not None:
f.write('%s\n' % (bad_line2))
def do_test(port, connack_rc, username, password):
rc = 1
keepalive = 60
connect_packet = mosq_test.gen_connect("username-password-check", keepalive=keepalive, username=username, password=password)
connack_packet = mosq_test.gen_connack(rc=connack_rc)
try:
sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port)
rc = 0
sock.close()
finally:
if rc:
exit(rc)
def username_password_tests(port):
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
try:
do_test(port, connack_rc=0, username='test', password='test')
do_test(port, connack_rc=5, username='test', password='bad')
do_test(port, connack_rc=5, username='test', password='')
do_test(port, connack_rc=5, username='test', password=None)
do_test(port, connack_rc=5, username='empty', password='test')
do_test(port, connack_rc=5, username='empty', password='bad')
do_test(port, connack_rc=5, username='empty', password='')
do_test(port, connack_rc=5, username='empty', password=None)
do_test(port, connack_rc=5, username='bad', password='test')
do_test(port, connack_rc=5, username='bad', password='bad')
do_test(port, connack_rc=5, username='bad', password='')
do_test(port, connack_rc=5, username='bad', password=None)
do_test(port, connack_rc=5, username='', password='test')
do_test(port, connack_rc=5, username='', password='bad')
do_test(port, connack_rc=5, username='', password='')
do_test(port, connack_rc=5, username='', password=None)
do_test(port, connack_rc=5, username=None, password='test')
do_test(port, connack_rc=5, username=None, password='bad')
do_test(port, connack_rc=5, username=None, password='')
do_test(port, connack_rc=5, username=None, password=None)
except ValueError:
pass
finally:
broker.terminate()
broker.wait()
def all_tests(port):
# Valid file, single user
write_pwfile(pw_file, bad_line1=None, bad_line2=None)
username_password_tests(port)
# Invalid file, first line blank
write_pwfile(pw_file, bad_line1='', bad_line2=None)
username_password_tests(port)
# Invalid file, last line blank
write_pwfile(pw_file, bad_line1=None, bad_line2='')
username_password_tests(port)
# Invalid file, first and last line blank
write_pwfile(pw_file, bad_line1='', bad_line2='')
username_password_tests(port)
# Invalid file, first line 'comment'
write_pwfile(pw_file, bad_line1='#comment', bad_line2=None)
username_password_tests(port)
# Invalid file, last line 'comment'
write_pwfile(pw_file, bad_line1=None, bad_line2='#comment')
username_password_tests(port)
# Invalid file, first and last line 'comment'
write_pwfile(pw_file, bad_line1='#comment', bad_line2='#comment')
username_password_tests(port)
# Invalid file, first line blank and last line 'comment'
write_pwfile(pw_file, bad_line1='', bad_line2='#comment')
username_password_tests(port)
# Invalid file, first line incomplete
write_pwfile(pw_file, bad_line1='bad:', bad_line2=None)
username_password_tests(port)
# Invalid file, first line incomplete, but with "password"
write_pwfile(pw_file, bad_line1='bad:bad', bad_line2=None)
username_password_tests(port)
# Invalid file, first line incomplete, partial password hash
write_pwfile(pw_file, bad_line1='bad:$', bad_line2=None)
username_password_tests(port)
# Invalid file, first line incomplete, partial password hash
write_pwfile(pw_file, bad_line1='bad:$6', bad_line2=None)
username_password_tests(port)
# Invalid file, first line incomplete, partial password hash
write_pwfile(pw_file, bad_line1='bad:$6$', bad_line2=None)
username_password_tests(port)
# Valid file, first line incomplete, has valid salt but no password hash
write_pwfile(pw_file, bad_line1='bad:$6$njERlZMi/7DzNB9E', bad_line2=None)
username_password_tests(port)
# Valid file, first line incomplete, has valid salt but no password hash
write_pwfile(pw_file, bad_line1='bad:$6$njERlZMi/7DzNB9E$', bad_line2=None)
username_password_tests(port)
# Valid file, first line has invalid hash designator
write_pwfile(pw_file, bad_line1='bad:$5$njERlZMi/7DzNB9E$iiavfuXvUm8iyDZArTy7smTxh07GXXOrOsqxfW6gkOYVXHGk+W+i/8d3xDxrMwEPygEBhoA8A/gjQC0N2M4Lkw==', bad_line2=None)
username_password_tests(port)
# Invalid file, missing username but valid password hash
write_pwfile(pw_file, bad_line1=':$6$njERlZMi/7DzNB9E$iiavfuXvUm8iyDZArTy7smTxh07GXXOrOsqxfW6gkOYVXHGk+W+i/8d3xDxrMwEPygEBhoA8A/gjQC0N2M4Lkw==', bad_line2=None)
username_password_tests(port)
# Valid file, valid username but password salt not base64
write_pwfile(pw_file, bad_line1='bad:$6$njER{ZMi/7DzNB9E$iiavfuXvUm8iyDZArTy7smTxh07GXXOrOsqxfW6gkOYVXHGk+W+i/8d3xDxrMwEPygEBhoA8A/gjQC0N2M4Lkw==', bad_line2=None)
username_password_tests(port)
# Valid file, valid username but password hash not base64
write_pwfile(pw_file, bad_line1='bad:$6$njERlZMi/7DzNB9E$iiavfuXv{}8iyDZArTy7smTxh07GXXOrOsqxfW6gkOYVXHGk+W+i/8d3xDxrMwEPygEBhoA8A/gjQC0N2M4Lkw==', bad_line2=None)
username_password_tests(port)
port = mosq_test.get_port()
conf_file = os.path.basename(__file__).replace('.py', '.conf')
pw_file = os.path.basename(__file__).replace('.py', '.pwfile')
try:
write_config(conf_file, port, "false")
all_tests(port)
write_config(conf_file, port, "true")
all_tests(port)
finally:
os.remove(conf_file)
os.remove(pw_file)

View File

@ -50,6 +50,11 @@ endif
./02-subpub-qos0.py
./02-subpub-qos1.py
./02-subpub-qos2.py
./02-subpub-qos1-bad-pubrec.py
./02-subpub-qos1-bad-pubcomp.py
./02-subpub-qos2-bad-puback-1.py
./02-subpub-qos2-bad-puback-2.py
./02-subpub-qos2-bad-pubcomp.py
./02-subpub-qos0-v5.py
./02-subpub-qos1-v5.py
./02-subpub-qos2-v5.py
@ -97,6 +102,9 @@ endif
./04-retain-qos1-qos0.py
./04-retain-qos0-clear.py
./04-retain-upgrade-outgoing-qos.py
./04-retain-check-source.py
./04-retain-check-source-persist.py
./04-retain-check-source-persist-diff-port.py
05 :
./05-clean-session-qos1.py
@ -139,6 +147,7 @@ endif
endif
09 :
./09-acl-empty-file.py
./09-plugin-auth-unpwd-success.py
./09-plugin-auth-unpwd-fail.py
./09-plugin-auth-acl-sub.py
@ -149,6 +158,7 @@ endif
./09-plugin-auth-defer-unpwd-fail.py
./09-plugin-auth-msg-params.py
./09-plugin-auth-context-params.py
./09-pwfile-parse-invalid.py
10 :
./10-listener-mount-point.py

View File

@ -33,6 +33,11 @@ tests = [
(1, './02-subpub-qos0.py'),
(1, './02-subpub-qos1.py'),
(1, './02-subpub-qos2.py'),
(1, './02-subpub-qos1-bad-pubrec.py'),
(1, './02-subpub-qos1-bad-pubcomp.py'),
(1, './02-subpub-qos2-bad-puback-1.py'),
(1, './02-subpub-qos2-bad-puback-2.py'),
(1, './02-subpub-qos2-bad-pubcomp.py'),
(1, './02-subpub-qos0-v5.py'),
(1, './02-subpub-qos1-v5.py'),
(1, './02-subpub-qos2-v5.py'),
@ -78,6 +83,9 @@ tests = [
(1, './04-retain-qos1-qos0.py'),
(1, './04-retain-qos0-clear.py'),
(1, './04-retain-upgrade-outgoing-qos.py'),
(1, './04-retain-check-source.py'),
(1, './04-retain-check-source-persist.py'),
(2, './04-retain-check-source-persist-diff-port.py'),
(1, './05-clean-session-qos1.py'),
@ -111,6 +119,7 @@ tests = [
(2, './08-tls-psk-pub.py'),
(3, './08-tls-psk-bridge.py'),
(1, './09-acl-empty-file.py'),
(1, './09-plugin-auth-unpwd-success.py'),
(1, './09-plugin-auth-unpwd-fail.py'),
(1, './09-plugin-auth-acl-sub.py'),
@ -121,6 +130,7 @@ tests = [
(1, './09-plugin-auth-defer-unpwd-fail.py'),
(1, './09-plugin-auth-msg-params.py'),
(1, './09-plugin-auth-context-params.py'),
(1, './09-pwfile-parse-invalid.py'),
(2, './10-listener-mount-point.py'),

View File

@ -8,7 +8,7 @@ import time
import mqtt5_props
def start_broker(filename, cmd=None, port=0, use_conf=False):
def start_broker(filename, cmd=None, port=0, use_conf=False, expect_fail=False):
delay = 0.1
if use_conf == True:
@ -45,7 +45,11 @@ def start_broker(filename, cmd=None, port=0, use_conf=False):
c.close()
time.sleep(delay)
return broker
raise IOError
if expect_fail == False:
raise IOError
else:
return None
def start_client(filename, cmd, env, port=1888):
if cmd is None:

View File

@ -12,7 +12,6 @@
# Source
* [mosquitto-1.5.5.tar.gz](https://mosquitto.org/files/source/mosquitto-1.5.5.tar.gz) (319kB) ([GPG signature](https://mosquitto.org/files/source/mosquitto-1.5.5.tar.gz.asc))
* [mosquitto-1.5.4.tar.gz](https://www.eclipse.org/downloads/download.php?file=/mosquitto/source/mosquitto-1.5.4.tar.gz) (via Eclipse)
* [Git source code repository](https://github.com/eclipse/mosquitto) (github.com)
Older downloads are available at [https://mosquitto.org/files/](../files/)
@ -25,8 +24,8 @@ distributions.
## Windows
* [mosquitto-1.5.4-install-windows-x64.exe](https://www.eclipse.org/downloads/download.php?file=/mosquitto/binary/win64/mosquitto-1.5.4-install-windows-x64.exe) (~360 kB) (64-bit build, Windows Vista and up, built with Visual Studio Community 2017)
* [mosquitto-1.5.4-install-windows-x32.exe](https://www.eclipse.org/downloads/download.php?file=/mosquitto/binary/win32/mosquitto-1.5.4-install-windows-x86.exe) (~360 kB) (32-bit build, Windows Vista and up, built with Visual Studio Community 2017)
* [mosquitto-1.5.5-install-windows-x64.exe](https://mosquitto.org/files/binary/win64/mosquitto-1.5.5-install-windows-x64.exe) (~360 kB) (64-bit build, Windows Vista and up, built with Visual Studio Community 2017)
* [mosquitto-1.5.5-install-windows-x32.exe](https://mosquitto.org/files/binary/win32/mosquitto-1.5.5-install-windows-x86.exe) (~360 kB) (32-bit build, Windows Vista and up, built with Visual Studio Community 2017)
See also readme-windows.txt after installing.

View File

@ -19,7 +19,7 @@ follow the steps on [Eclipse Security] page to report it.
Listed with most recent first. Further information on security related issues
can be found in the [security category].
* December 2018: No CVE assigned. Affecting versions **1.5** to **1.5.4**
* December 2018: [CVE-2018-20145]. Affecting versions **1.5** to **1.5.4**
inclusive, fixed in **1.5.5.**. More details at [version-155-released].
* November 2018: No CVE assigned. Affecting versions **1.4** to **1.5.3**
inclusive, fixed in **1.5.4**. More details at [version-154-released].
@ -55,6 +55,7 @@ can be found in the [security category].
[Eclipse Security]: https://www.eclipse.org/security/
[security category]: /blog/categories/security/
[CVE-2018-20145]: https://nvd.nist.gov/vuln/detail/CVE-2018-20145
[CVE-2018-12543]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-12543
[CVE-2017-9868]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-9868
[CVE-2017-7655]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7652

View File

@ -17,6 +17,7 @@ This is a bugfix and security release.
- If `per_listener_settings` is set to true, then the `acl_file` setting was
ignored for the "default listener" only. This has been fixed. This does not
affect any listeners defined with the `listener` option. Closes [#1073].
This is now tracked as [CVE-2018-20145].
## Broker
- Add `socket_domain` option to allow listeners to disable IPv6 support.
@ -46,6 +47,7 @@ This is a bugfix and security release.
- Fix building where TLS-PSK is not available. Closes [#68].
[CVE-2018-20145]: https://nvd.nist.gov/vuln/detail/CVE-2018-20145
[#68]: https://github.com/eclipse/mosquitto/issues/68
[#537]: https://github.com/eclipse/mosquitto/issues/537
[#613]: https://github.com/eclipse/mosquitto/issues/613