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:
commit
084062c85e
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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})
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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}")
|
||||
|
||||
|
@ -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}")
|
||||
|
||||
|
@ -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){
|
||||
|
@ -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){
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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. -->
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
MAJOR=1
|
||||
MINOR=5
|
||||
REVISION=5
|
||||
REVISION=6
|
||||
|
||||
sed -i "s/^VERSION=.*/VERSION=${MAJOR}.${MINOR}.${REVISION}/" config.mk
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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, ¬ification_payload, 1, NULL);
|
||||
db__messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, ¬ification_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, ¬ification_payload, 1, NULL);
|
||||
db__messages_easy_queue(db, context, notification_topic, 1, 1, ¬ification_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);
|
||||
|
124
src/conf.c
124
src/conf.c
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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{
|
||||
|
@ -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
|
||||
|
||||
|
@ -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){
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
14
src/loop.c
14
src/loop.c
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
185
src/persist.c
185
src/persist.c
@ -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);
|
||||
|
@ -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'};
|
||||
|
@ -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)){
|
||||
|
21
src/subs.c
21
src/subs.c
@ -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 {
|
||||
|
@ -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;
|
||||
|
69
test/broker/02-subpub-qos1-bad-pubcomp.py
Executable file
69
test/broker/02-subpub-qos1-bad-pubcomp.py
Executable 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)
|
||||
|
65
test/broker/02-subpub-qos1-bad-pubrec.py
Executable file
65
test/broker/02-subpub-qos1-bad-pubrec.py
Executable 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)
|
||||
|
68
test/broker/02-subpub-qos2-bad-puback-1.py
Executable file
68
test/broker/02-subpub-qos2-bad-puback-1.py
Executable 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)
|
||||
|
71
test/broker/02-subpub-qos2-bad-puback-2.py
Executable file
71
test/broker/02-subpub-qos2-bad-puback-2.py
Executable 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)
|
||||
|
68
test/broker/02-subpub-qos2-bad-pubcomp.py
Executable file
68
test/broker/02-subpub-qos2-bad-pubcomp.py
Executable 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)
|
||||
|
117
test/broker/04-retain-check-source-persist-diff-port.py
Executable file
117
test/broker/04-retain-check-source-persist-diff-port.py
Executable 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")
|
106
test/broker/04-retain-check-source-persist.py
Executable file
106
test/broker/04-retain-check-source-persist.py
Executable 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")
|
87
test/broker/04-retain-check-source.py
Executable file
87
test/broker/04-retain-check-source.py
Executable 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")
|
71
test/broker/09-acl-empty-file.py
Executable file
71
test/broker/09-acl-empty-file.py
Executable 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")
|
169
test/broker/09-pwfile-parse-invalid.py
Executable file
169
test/broker/09-pwfile-parse-invalid.py
Executable 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)
|
@ -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
|
||||
|
@ -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'),
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user