mirror of
https://github.com/eclipse/mosquitto.git
synced 2025-04-19 10:22:16 +03:00
Merge branch 'fixes'
This commit is contained in:
commit
9e0831b3ed
81
.github/workflows/windows.yml
vendored
Normal file
81
.github/workflows/windows.yml
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
name: Windows build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ "master", "fixes" ]
|
||||
tags: [ "v[0-9]+.*" ]
|
||||
pull_request:
|
||||
branches: [ "master", "fixes" ]
|
||||
|
||||
env:
|
||||
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
|
||||
cjson:
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
repository: DaveGamble/cJSON
|
||||
ref: v1.7.15
|
||||
|
||||
- name: Configure CMake cJSON
|
||||
run: cmake -B ${{github.workspace}}/build64 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_CJSON_TEST=OFF -DBUILD_SHARED_LIBS=OFF -DBUILD_SHARED_AND_STATIC_LIBS=OFF -DCJSON_BUILD_SHARED_LIBS=OFF -DCJSON_OVERRIDE_BUILD_SHARED_LIBS=OFF -DCMAKE_GENERATOR_PLATFORM=x64
|
||||
|
||||
- name: Build cJSON
|
||||
run: cmake --build ${{github.workspace}}/build64 --config ${{env.BUILD_TYPE}}
|
||||
|
||||
- name: Install cJSON
|
||||
run: cmake --install ${{github.workspace}}/build64 --config ${{env.BUILD_TYPE}}
|
||||
|
||||
- name: Upload cJSON
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cjson-bin
|
||||
path: C:\Program Files\cJSON
|
||||
|
||||
mosquitto:
|
||||
runs-on: windows-2022
|
||||
needs:
|
||||
- cjson
|
||||
env:
|
||||
CJSON_DIR: C:\Program Files\cJSON
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: install openssl
|
||||
run: choco install openssl
|
||||
|
||||
- name: Download cJSON
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: cjson-bin
|
||||
path: C:\Program Files\cJSON
|
||||
|
||||
- name: Configure CMake
|
||||
run: cmake -B ${{github.workspace}}/build64 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DWITH_TESTS=OFF -DCMAKE_GENERATOR_PLATFORM=x64 -DCJSON_INCLUDE_DIR="C:/Program Files/cJSON/include" -DCJSON_LIBRARY="C:/Program Files/cJSON/lib/cjson.lib"
|
||||
|
||||
- name: Build
|
||||
run: cmake --build ${{github.workspace}}/build64 --config ${{env.BUILD_TYPE}}
|
||||
|
||||
- uses: suisei-cn/actions-download-file@v1.0.1
|
||||
id: vcredist
|
||||
name: Download VC redistributable
|
||||
with:
|
||||
url: https://aka.ms/vs/17/release/vc_redist.x64.exe
|
||||
target: ${{github.workspace}}/installer/
|
||||
|
||||
- name: Installer
|
||||
uses: joncloud/makensis-action@v3.7
|
||||
with:
|
||||
script-file: ${{github.workspace}}/installer/mosquitto.nsi
|
||||
|
||||
- name: Upload installer to artifacts
|
||||
uses: actions/upload-artifact/@v2
|
||||
with:
|
||||
name: installer
|
||||
path: ${{ github.workspace }}/installer/mosquitto*.exe
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -82,6 +82,7 @@ test/unit/mosq_test
|
||||
test/unit/persist_read_test
|
||||
test/unit/persist_write_test
|
||||
test/unit/subs_test
|
||||
test/unit/tls_test
|
||||
test/unit/out/
|
||||
|
||||
www/cache/
|
||||
|
@ -8,7 +8,7 @@ cmake_minimum_required(VERSION 3.1)
|
||||
cmake_policy(SET CMP0042 NEW)
|
||||
|
||||
project(mosquitto)
|
||||
set (VERSION 2.0.15)
|
||||
set (VERSION 2.0.16)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/")
|
||||
|
||||
|
@ -1,3 +1,62 @@
|
||||
2.0.16 - 2023-08-16
|
||||
===================
|
||||
|
||||
Security:
|
||||
- CVE-2023-28366: Fix memory leak in broker when clients send multiple QoS 2
|
||||
messages with the same message ID, but then never respond to the PUBREC
|
||||
commands.
|
||||
- CVE-2023-0809: Fix excessive memory being allocated based on malicious
|
||||
initial packets that are not CONNECT packets.
|
||||
- CVE-2023-3592: Fix memory leak when clients send v5 CONNECT packets with a
|
||||
will message that contains invalid property types.
|
||||
- Broker will now reject Will messages that attempt to publish to $CONTROL/.
|
||||
- Broker now validates usernames provided in a TLS certificate or TLS-PSK
|
||||
identity are valid UTF-8.
|
||||
- Fix potential crash when loading invalid persistence file.
|
||||
- Library will no longer allow single level wildcard certificates, e.g. *.com
|
||||
|
||||
Broker:
|
||||
- Fix $SYS messages being expired after 60 seconds and hence unchanged values
|
||||
disappearing.
|
||||
- Fix some retained topic memory not being cleared immediately after used.
|
||||
- Fix error handling related to the `bind_interface` option.
|
||||
- Fix std* files not being redirected when daemonising, when built with
|
||||
assertions removed. Closes #2708.
|
||||
- Fix default settings incorrectly allowing TLS v1.1. Closes #2722.
|
||||
- Use line buffered mode for stdout. Closes #2354. Closes #2749.
|
||||
- Fix bridges with non-matching cleansession/local_cleansession being expired
|
||||
on start after restoring from persistence. Closes #2634.
|
||||
- Fix connections being limited to 2048 on Windows. The limit is now 8192,
|
||||
where supported. Closes #2732.
|
||||
- Broker will log warnings if sensitive files are world readable/writable, or
|
||||
if the owner/group is not the same as the user/group the broker is running
|
||||
as. In future versions the broker will refuse to open these files.
|
||||
- mosquitto_memcmp_const is now more constant time.
|
||||
- Only register with DLT if DLT logging is enabled.
|
||||
- Fix any possible case where a json string might be incorrectly loaded. This
|
||||
could have caused a crash if a textname or textdescription field of a role was
|
||||
not a string, when loading the dynsec config from file only.
|
||||
- Dynsec plugin will not allow duplicate clients/groups/roles when loading
|
||||
config from file, which matches the behaviour for when creating them.
|
||||
- Fix heap overflow when reading corrupt config with "log_dest file".
|
||||
|
||||
Client library:
|
||||
- Use CLOCK_BOOTTIME when available, to keep track of time. This solves the
|
||||
problem of the client OS sleeping and the client hence not being able to
|
||||
calculate the actual time for keepalive purposes. Closes #2760.
|
||||
- Fix default settings incorrectly allowing TLS v1.1. Closes #2722.
|
||||
- Fix high CPU use on slow TLS connect. Closes #2794.
|
||||
|
||||
Clients:
|
||||
- Fix incorrect topic-alias property value in mosquitto_sub json output.
|
||||
- Fix confusing message on TLS certificate verification. Closes #2746.
|
||||
|
||||
Apps:
|
||||
- mosquitto_passwd uses mkstemp() for backup files.
|
||||
- `mosquitto_ctrl dynsec init` will refuse to overwrite an existing file,
|
||||
without a race-condition.
|
||||
|
||||
|
||||
2.0.15 - 2022-08-16
|
||||
===================
|
||||
|
||||
|
@ -82,7 +82,3 @@ Equivalent options for enabling/disabling features are available when using the
|
||||
## Credits
|
||||
|
||||
Mosquitto was written by Roger Light <roger@atchoo.org>
|
||||
|
||||
Master: [](https://travis-ci.org/eclipse/mosquitto)
|
||||
Develop: [](https://travis-ci.org/eclipse/mosquitto)
|
||||
Fixes: [](https://travis-ci.org/eclipse/mosquitto)
|
||||
|
@ -16,7 +16,6 @@ Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
@ -17,6 +17,7 @@ if (WITH_TLS AND CJSON_FOUND)
|
||||
dynsec_role.c
|
||||
../mosquitto_passwd/get_password.c ../mosquitto_passwd/get_password.h
|
||||
../../lib/memory_mosq.c ../../lib/memory_mosq.h
|
||||
../../lib/misc_mosq.c ../../lib/misc_mosq.h
|
||||
../../src/memory_public.c
|
||||
options.c
|
||||
../../src/password_mosq.c ../../src/password_mosq.h
|
||||
|
@ -23,6 +23,7 @@ OBJS= mosquitto_ctrl.o \
|
||||
get_password.o \
|
||||
memory_mosq.o \
|
||||
memory_public.o \
|
||||
misc_mosq.o \
|
||||
options.o \
|
||||
password_mosq.o
|
||||
|
||||
|
@ -23,6 +23,8 @@ Contributors:
|
||||
#include <string.h>
|
||||
|
||||
#ifndef WIN32
|
||||
# include <errno.h>
|
||||
# include <fcntl.h>
|
||||
# include <strings.h>
|
||||
#endif
|
||||
|
||||
@ -30,6 +32,7 @@ Contributors:
|
||||
#include "mosquitto.h"
|
||||
#include "password_mosq.h"
|
||||
#include "get_password.h"
|
||||
#include "misc_mosq.h"
|
||||
|
||||
void dynsec__print_usage(void)
|
||||
{
|
||||
@ -738,13 +741,6 @@ static int dynsec_init(int argc, char *argv[])
|
||||
admin_password = password;
|
||||
}
|
||||
|
||||
fptr = fopen(filename, "rb");
|
||||
if(fptr){
|
||||
fclose(fptr);
|
||||
fprintf(stderr, "dynsec init: '%s' already exists. Remove the file or use a different location..\n", filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
tree = init_create(admin_user, admin_password, "admin");
|
||||
if(tree == NULL){
|
||||
fprintf(stderr, "dynsec init: Out of memory.\n");
|
||||
@ -753,7 +749,17 @@ static int dynsec_init(int argc, char *argv[])
|
||||
json_str = cJSON_Print(tree);
|
||||
cJSON_Delete(tree);
|
||||
|
||||
fptr = fopen(filename, "wb");
|
||||
#ifdef WIN32
|
||||
fptr = mosquitto__fopen(filename, "wb", true);
|
||||
#else
|
||||
int fd = open(filename, O_CREAT | O_EXCL | O_WRONLY, 0640);
|
||||
if(fd < 0){
|
||||
free(json_str);
|
||||
fprintf(stderr, "dynsec init: Unable to open '%s' for writing (%s).\n", filename, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
fptr = fdopen(fd, "wb");
|
||||
#endif
|
||||
if(fptr){
|
||||
fprintf(fptr, "%s", json_str);
|
||||
free(json_str);
|
||||
|
@ -593,6 +593,11 @@ int client_opts_set(struct mosquitto *mosq, struct mosq_config *cfg)
|
||||
return 1;
|
||||
}
|
||||
#ifdef WITH_TLS
|
||||
if(cfg->keyform && mosquitto_string_option(mosq, MOSQ_OPT_TLS_KEYFORM, cfg->keyform)){
|
||||
fprintf(stderr, "Error: Problem setting key form, it must be one of 'pem' or 'engine'.\n");
|
||||
mosquitto_lib_cleanup();
|
||||
return 1;
|
||||
}
|
||||
if(cfg->cafile || cfg->capath){
|
||||
rc = mosquitto_tls_set(mosq, cfg->cafile, cfg->capath, cfg->certfile, cfg->keyfile, NULL);
|
||||
if(rc){
|
||||
@ -615,11 +620,6 @@ int client_opts_set(struct mosquitto *mosq, struct mosq_config *cfg)
|
||||
mosquitto_lib_cleanup();
|
||||
return 1;
|
||||
}
|
||||
if(cfg->keyform && mosquitto_string_option(mosq, MOSQ_OPT_TLS_KEYFORM, cfg->keyform)){
|
||||
fprintf(stderr, "Error: Problem setting key form, it must be one of 'pem' or 'engine'.\n");
|
||||
mosquitto_lib_cleanup();
|
||||
return 1;
|
||||
}
|
||||
if(cfg->tls_engine_kpass_sha1 && mosquitto_string_option(mosq, MOSQ_OPT_TLS_ENGINE_KPASS_SHA1, cfg->tls_engine_kpass_sha1)){
|
||||
fprintf(stderr, "Error: Problem setting TLS engine key pass sha, is it a 40 character hex string?\n");
|
||||
mosquitto_lib_cleanup();
|
||||
|
@ -370,15 +370,27 @@ static int copy_contents(FILE *src, FILE *dest)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int create_backup(const char *backup_file, FILE *fptr)
|
||||
static int create_backup(char *backup_file, FILE *fptr)
|
||||
{
|
||||
FILE *fbackup;
|
||||
|
||||
fbackup = fopen(backup_file, "wt");
|
||||
#ifdef WIN32
|
||||
fbackup = mosquitto__fopen(backup_file, "wt", true);
|
||||
#else
|
||||
int fd;
|
||||
umask(077);
|
||||
fd = mkstemp(backup_file);
|
||||
if(fd < 0){
|
||||
fprintf(stderr, "Error creating backup password file \"%s\", not continuing.\n", backup_file);
|
||||
return 1;
|
||||
}
|
||||
fbackup = fdopen(fd, "wt");
|
||||
#endif
|
||||
if(!fbackup){
|
||||
fprintf(stderr, "Error creating backup password file \"%s\", not continuing.\n", backup_file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(copy_contents(fptr, fbackup)){
|
||||
fprintf(stderr, "Error copying data to backup password file \"%s\", not continuing.\n", backup_file);
|
||||
fclose(fbackup);
|
||||
@ -599,7 +611,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
password_cmd = password;
|
||||
}
|
||||
fptr = fopen(password_file, "wt");
|
||||
fptr = mosquitto__fopen(password_file, "wt", true);
|
||||
if(!fptr){
|
||||
fprintf(stderr, "Error: Unable to open file %s for writing. %s.\n", password_file, strerror(errno));
|
||||
free(password_file);
|
||||
@ -610,20 +622,20 @@ int main(int argc, char *argv[])
|
||||
fclose(fptr);
|
||||
return rc;
|
||||
}else{
|
||||
fptr = fopen(password_file, "r+t");
|
||||
fptr = mosquitto__fopen(password_file, "r+t", true);
|
||||
if(!fptr){
|
||||
fprintf(stderr, "Error: Unable to open password file %s. %s.\n", password_file, strerror(errno));
|
||||
free(password_file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
backup_file = malloc((size_t)strlen(password_file)+5);
|
||||
backup_file = malloc((size_t)strlen(password_file)+strlen(".backup.XXXXXX"));
|
||||
if(!backup_file){
|
||||
fprintf(stderr, "Error: Out of memory.\n");
|
||||
free(password_file);
|
||||
return 1;
|
||||
}
|
||||
snprintf(backup_file, strlen(password_file)+5, "%s.tmp", password_file);
|
||||
snprintf(backup_file, strlen(password_file)+5, "%s.backup.XXXXXX", password_file);
|
||||
free(password_file);
|
||||
password_file = NULL;
|
||||
|
||||
|
@ -1253,6 +1253,11 @@ int client_opts_set(struct mosquitto *mosq, struct mosq_config *cfg)
|
||||
return 1;
|
||||
}
|
||||
#ifdef WITH_TLS
|
||||
if(cfg->keyform && mosquitto_string_option(mosq, MOSQ_OPT_TLS_KEYFORM, cfg->keyform)){
|
||||
err_printf(cfg, "Error: Problem setting key form, it must be one of 'pem' or 'engine'.\n");
|
||||
mosquitto_lib_cleanup();
|
||||
return 1;
|
||||
}
|
||||
if(cfg->cafile || cfg->capath){
|
||||
rc = mosquitto_tls_set(mosq, cfg->cafile, cfg->capath, cfg->certfile, cfg->keyfile, NULL);
|
||||
if(rc){
|
||||
@ -1289,11 +1294,6 @@ int client_opts_set(struct mosquitto *mosq, struct mosq_config *cfg)
|
||||
mosquitto_lib_cleanup();
|
||||
return 1;
|
||||
}
|
||||
if(cfg->keyform && mosquitto_string_option(mosq, MOSQ_OPT_TLS_KEYFORM, cfg->keyform)){
|
||||
err_printf(cfg, "Error: Problem setting key form, it must be one of 'pem' or 'engine'.\n");
|
||||
mosquitto_lib_cleanup();
|
||||
return 1;
|
||||
}
|
||||
if(cfg->tls_engine_kpass_sha1 && mosquitto_string_option(mosq, MOSQ_OPT_TLS_ENGINE_KPASS_SHA1, cfg->tls_engine_kpass_sha1)){
|
||||
err_printf(cfg, "Error: Problem setting TLS engine key pass sha, is it a 40 character hex string?\n");
|
||||
mosquitto_lib_cleanup();
|
||||
|
@ -210,7 +210,7 @@ static int json_print_properties(cJSON *root, const mosquitto_property *properti
|
||||
break;
|
||||
|
||||
case MQTT_PROP_TOPIC_ALIAS:
|
||||
mosquitto_property_read_int16(prop, MQTT_PROP_MESSAGE_EXPIRY_INTERVAL, &i16value, false);
|
||||
mosquitto_property_read_int16(prop, MQTT_PROP_TOPIC_ALIAS, &i16value, false);
|
||||
tmp = cJSON_CreateNumber(i16value);
|
||||
break;
|
||||
|
||||
|
@ -127,7 +127,7 @@ WITH_XTREPORT=no
|
||||
|
||||
# Also bump lib/mosquitto.h, CMakeLists.txt,
|
||||
# installer/mosquitto.nsi, installer/mosquitto64.nsi
|
||||
VERSION=2.0.15
|
||||
VERSION=2.0.16
|
||||
|
||||
# Client library SO version. Bump if incompatible API/ABI changes are made.
|
||||
SOVERSION=1
|
||||
|
@ -66,7 +66,7 @@ extern "C" {
|
||||
|
||||
#define LIBMOSQUITTO_MAJOR 2
|
||||
#define LIBMOSQUITTO_MINOR 0
|
||||
#define LIBMOSQUITTO_REVISION 15
|
||||
#define LIBMOSQUITTO_REVISION 16
|
||||
/* 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)
|
||||
|
||||
@ -497,8 +497,8 @@ libmosq_EXPORT int mosquitto_username_pw_set(struct mosquitto *mosq, const char
|
||||
* mosq - a valid mosquitto instance.
|
||||
* host - the hostname or ip address of the broker to connect to.
|
||||
* port - the network port to connect to. Usually 1883.
|
||||
* keepalive - the number of seconds after which the broker should send a PING
|
||||
* message to the client if no other messages have been exchanged
|
||||
* keepalive - the number of seconds after which the client should send a PING
|
||||
* message to the broker if no other messages have been exchanged
|
||||
* in that time.
|
||||
*
|
||||
* Returns:
|
||||
@ -529,8 +529,8 @@ libmosq_EXPORT int mosquitto_connect(struct mosquitto *mosq, const char *host, i
|
||||
* mosq - a valid mosquitto instance.
|
||||
* host - the hostname or ip address of the broker to connect to.
|
||||
* port - the network port to connect to. Usually 1883.
|
||||
* keepalive - the number of seconds after which the broker should send a PING
|
||||
* message to the client if no other messages have been exchanged
|
||||
* keepalive - the number of seconds after which the client should send a PING
|
||||
* message to the broker if no other messages have been exchanged
|
||||
* in that time.
|
||||
* bind_address - the hostname or ip address of the local network interface to
|
||||
* bind to. If you do not want to bind to a specific interface,
|
||||
@ -573,8 +573,8 @@ libmosq_EXPORT int mosquitto_connect_bind(struct mosquitto *mosq, const char *ho
|
||||
* mosq - a valid mosquitto instance.
|
||||
* host - the hostname or ip address of the broker to connect to.
|
||||
* port - the network port to connect to. Usually 1883.
|
||||
* keepalive - the number of seconds after which the broker should send a PING
|
||||
* message to the client if no other messages have been exchanged
|
||||
* keepalive - the number of seconds after which the client should send a PING
|
||||
* message to the broker if no other messages have been exchanged
|
||||
* in that time.
|
||||
* bind_address - the hostname or ip address of the local network interface to
|
||||
* bind to. If you do not want to bind to a specific interface,
|
||||
@ -614,8 +614,8 @@ libmosq_EXPORT int mosquitto_connect_bind_v5(struct mosquitto *mosq, const char
|
||||
* mosq - a valid mosquitto instance.
|
||||
* host - the hostname or ip address of the broker to connect to.
|
||||
* port - the network port to connect to. Usually 1883.
|
||||
* keepalive - the number of seconds after which the broker should send a PING
|
||||
* message to the client if no other messages have been exchanged
|
||||
* keepalive - the number of seconds after which the client should send a PING
|
||||
* message to the broker if no other messages have been exchanged
|
||||
* in that time.
|
||||
*
|
||||
* Returns:
|
||||
@ -649,8 +649,8 @@ libmosq_EXPORT int mosquitto_connect_async(struct mosquitto *mosq, const char *h
|
||||
* mosq - a valid mosquitto instance.
|
||||
* host - the hostname or ip address of the broker to connect to.
|
||||
* port - the network port to connect to. Usually 1883.
|
||||
* keepalive - the number of seconds after which the broker should send a PING
|
||||
* message to the client if no other messages have been exchanged
|
||||
* keepalive - the number of seconds after which the client should send a PING
|
||||
* message to the broker if no other messages have been exchanged
|
||||
* in that time.
|
||||
* bind_address - the hostname or ip address of the local network interface to
|
||||
* bind to. If you do not want to bind to a specific interface,
|
||||
@ -688,8 +688,8 @@ libmosq_EXPORT int mosquitto_connect_bind_async(struct mosquitto *mosq, const ch
|
||||
* Parameters:
|
||||
* mosq - a valid mosquitto instance.
|
||||
* host - the hostname to search for an SRV record.
|
||||
* keepalive - the number of seconds after which the broker should send a PING
|
||||
* message to the client if no other messages have been exchanged
|
||||
* keepalive - the number of seconds after which the client should send a PING
|
||||
* message to the broker if no other messages have been exchanged
|
||||
* in that time.
|
||||
* bind_address - the hostname or ip address of the local network interface to
|
||||
* bind to. If you do not want to bind to a specific interface,
|
||||
|
@ -9,7 +9,7 @@
|
||||
!define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
|
||||
|
||||
Name "Eclipse Mosquitto"
|
||||
!define VERSION 2.0.15
|
||||
!define VERSION 2.0.16
|
||||
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 2.0.15
|
||||
!define VERSION 2.0.16
|
||||
OutFile "mosquitto-${VERSION}-install-windows-x64.exe"
|
||||
|
||||
!include "x64.nsh"
|
||||
|
@ -100,6 +100,7 @@ int handle__pubackcomp(struct mosquitto *mosq, const char *type)
|
||||
&& reason_code != MQTT_RC_PAYLOAD_FORMAT_INVALID
|
||||
){
|
||||
|
||||
mosquitto_property_free_all(&properties);
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
}else{
|
||||
@ -107,14 +108,13 @@ int handle__pubackcomp(struct mosquitto *mosq, const char *type)
|
||||
&& reason_code != MQTT_RC_PACKET_ID_NOT_FOUND
|
||||
){
|
||||
|
||||
mosquitto_property_free_all(&properties);
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(mosq->in_packet.pos < mosq->in_packet.remaining_length){
|
||||
#ifdef WITH_BROKER
|
||||
mosquitto_property_free_all(&properties);
|
||||
#endif
|
||||
return MOSQ_ERR_MALFORMED_PACKET;
|
||||
}
|
||||
|
||||
|
22
lib/loop.c
22
lib/loop.c
@ -63,20 +63,22 @@ int mosquitto_loop(struct mosquitto *mosq, int timeout, int max_packets)
|
||||
if(mosq->sock != INVALID_SOCKET){
|
||||
maxfd = mosq->sock;
|
||||
FD_SET(mosq->sock, &readfds);
|
||||
pthread_mutex_lock(&mosq->current_out_packet_mutex);
|
||||
pthread_mutex_lock(&mosq->out_packet_mutex);
|
||||
if(mosq->out_packet || mosq->current_out_packet){
|
||||
if(mosq->want_write){
|
||||
FD_SET(mosq->sock, &writefds);
|
||||
}
|
||||
}else{
|
||||
#ifdef WITH_TLS
|
||||
if(mosq->ssl){
|
||||
if(mosq->want_write){
|
||||
FD_SET(mosq->sock, &writefds);
|
||||
if(mosq->ssl == NULL || SSL_is_init_finished(mosq->ssl))
|
||||
#endif
|
||||
{
|
||||
pthread_mutex_lock(&mosq->current_out_packet_mutex);
|
||||
pthread_mutex_lock(&mosq->out_packet_mutex);
|
||||
if(mosq->out_packet || mosq->current_out_packet){
|
||||
FD_SET(mosq->sock, &writefds);
|
||||
}
|
||||
pthread_mutex_unlock(&mosq->out_packet_mutex);
|
||||
pthread_mutex_unlock(&mosq->current_out_packet_mutex);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
pthread_mutex_unlock(&mosq->out_packet_mutex);
|
||||
pthread_mutex_unlock(&mosq->current_out_packet_mutex);
|
||||
}else{
|
||||
#ifdef WITH_SRV
|
||||
if(mosq->achan){
|
||||
|
@ -22,6 +22,8 @@ Contributors:
|
||||
#include "config.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -33,8 +35,12 @@ Contributors:
|
||||
# include <io.h>
|
||||
# include <lmcons.h>
|
||||
# include <fcntl.h>
|
||||
# define PATH_MAX MAX_PATH
|
||||
#else
|
||||
# include <sys/stat.h>
|
||||
# include <pwd.h>
|
||||
# include <grp.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "misc_mosq.h"
|
||||
@ -126,30 +132,87 @@ FILE *mosquitto__fopen(const char *path, const char *mode, bool restrict_read)
|
||||
}
|
||||
}
|
||||
#else
|
||||
if(mode[0] == 'r'){
|
||||
struct stat statbuf;
|
||||
if(stat(path, &statbuf) < 0){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!S_ISREG(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)){
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error: %s is not a file.", path);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
FILE *fptr;
|
||||
struct stat statbuf;
|
||||
|
||||
if (restrict_read) {
|
||||
FILE *fptr;
|
||||
mode_t old_mask;
|
||||
|
||||
old_mask = umask(0077);
|
||||
fptr = fopen(path, mode);
|
||||
umask(old_mask);
|
||||
|
||||
return fptr;
|
||||
}else{
|
||||
return fopen(path, mode);
|
||||
fptr = fopen(path, mode);
|
||||
}
|
||||
if(!fptr) return NULL;
|
||||
|
||||
if(fstat(fileno(fptr), &statbuf) < 0){
|
||||
fclose(fptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(restrict_read){
|
||||
if(statbuf.st_mode & S_IRWXO){
|
||||
#ifdef WITH_BROKER
|
||||
log__printf(NULL, MOSQ_LOG_WARNING,
|
||||
#else
|
||||
fprintf(stderr,
|
||||
#endif
|
||||
"Warning: File %s has world readable permissions. Future versions will refuse to load this file.",
|
||||
path);
|
||||
#if 0
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
if(statbuf.st_uid != getuid()){
|
||||
char buf[4096];
|
||||
struct passwd pw, *result;
|
||||
|
||||
getpwuid_r(getuid(), &pw, buf, sizeof(buf), &result);
|
||||
if(result){
|
||||
#ifdef WITH_BROKER
|
||||
log__printf(NULL, MOSQ_LOG_WARNING,
|
||||
#else
|
||||
fprintf(stderr,
|
||||
#endif
|
||||
"Warning: File %s owner is not %s. Future versions will refuse to load this file.",
|
||||
path, result->pw_name);
|
||||
}
|
||||
#if 0
|
||||
// Future version
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
if(statbuf.st_gid != getgid()){
|
||||
char buf[4096];
|
||||
struct group grp, *result;
|
||||
|
||||
getgrgid_r(getgid(), &grp, buf, sizeof(buf), &result);
|
||||
if(result){
|
||||
#ifdef WITH_BROKER
|
||||
log__printf(NULL, MOSQ_LOG_WARNING,
|
||||
#else
|
||||
fprintf(stderr,
|
||||
#endif
|
||||
"Warning: File %s group is not %s. Future versions will refuse to load this file.",
|
||||
path, result->gr_name);
|
||||
}
|
||||
#if 0
|
||||
// Future version
|
||||
return NULL
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!S_ISREG(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)){
|
||||
#ifdef WITH_BROKER
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error: %s is not a file.", path);
|
||||
#endif
|
||||
fclose(fptr);
|
||||
return NULL;
|
||||
}
|
||||
return fptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -61,8 +61,11 @@ int mosquitto_lib_init(void)
|
||||
srand((unsigned int)GetTickCount64());
|
||||
#elif _POSIX_TIMERS>0 && defined(_POSIX_MONOTONIC_CLOCK)
|
||||
struct timespec tp;
|
||||
|
||||
#ifdef CLOCK_BOOTTIME
|
||||
clock_gettime(CLOCK_BOOTTIME, &tp);
|
||||
#else
|
||||
clock_gettime(CLOCK_MONOTONIC, &tp);
|
||||
#endif
|
||||
srand((unsigned int)tp.tv_nsec);
|
||||
#elif defined(__APPLE__)
|
||||
uint64_t ticks;
|
||||
@ -329,18 +332,7 @@ int mosquitto_socket(struct mosquitto *mosq)
|
||||
|
||||
bool mosquitto_want_write(struct mosquitto *mosq)
|
||||
{
|
||||
bool result = false;
|
||||
if(mosq->out_packet || mosq->current_out_packet){
|
||||
result = true;
|
||||
}
|
||||
#ifdef WITH_TLS
|
||||
if(mosq->ssl){
|
||||
if (mosq->want_write) {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
return mosq->out_packet || mosq->current_out_packet || mosq->want_write;
|
||||
}
|
||||
|
||||
|
||||
|
@ -684,7 +684,7 @@ static int net__init_ssl_ctx(struct mosquitto *mosq)
|
||||
#endif
|
||||
|
||||
if(!mosq->tls_version){
|
||||
SSL_CTX_set_options(mosq->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1);
|
||||
SSL_CTX_set_options(mosq->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
|
||||
#ifdef SSL_OP_NO_TLSv1_3
|
||||
}else if(!strcmp(mosq->tls_version, "tlsv1.3")){
|
||||
SSL_CTX_set_options(mosq->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2);
|
||||
|
@ -179,19 +179,21 @@ int mosquitto_tls_set(struct mosquitto *mosq, const char *cafile, const char *ca
|
||||
mosquitto__free(mosq->tls_keyfile);
|
||||
mosq->tls_keyfile = NULL;
|
||||
if(keyfile){
|
||||
fptr = mosquitto__fopen(keyfile, "rt", false);
|
||||
if(fptr){
|
||||
fclose(fptr);
|
||||
}else{
|
||||
mosquitto__free(mosq->tls_cafile);
|
||||
mosq->tls_cafile = NULL;
|
||||
if(mosq->tls_keyform == mosq_k_pem){
|
||||
fptr = mosquitto__fopen(keyfile, "rt", false);
|
||||
if(fptr){
|
||||
fclose(fptr);
|
||||
}else{
|
||||
mosquitto__free(mosq->tls_cafile);
|
||||
mosq->tls_cafile = NULL;
|
||||
|
||||
mosquitto__free(mosq->tls_capath);
|
||||
mosq->tls_capath = NULL;
|
||||
mosquitto__free(mosq->tls_capath);
|
||||
mosq->tls_capath = NULL;
|
||||
|
||||
mosquitto__free(mosq->tls_certfile);
|
||||
mosq->tls_certfile = NULL;
|
||||
return MOSQ_ERR_INVAL;
|
||||
mosquitto__free(mosq->tls_certfile);
|
||||
mosq->tls_certfile = NULL;
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
}
|
||||
mosq->tls_keyfile = mosquitto__strdup(keyfile);
|
||||
if(!mosq->tls_keyfile){
|
||||
@ -228,19 +230,23 @@ int mosquitto_tls_opts_set(struct mosquitto *mosq, int cert_reqs, const char *tl
|
||||
|| !strcasecmp(tls_version, "tlsv1.2")
|
||||
|| !strcasecmp(tls_version, "tlsv1.1")){
|
||||
|
||||
mosquitto__free(mosq->tls_version);
|
||||
mosq->tls_version = mosquitto__strdup(tls_version);
|
||||
if(!mosq->tls_version) return MOSQ_ERR_NOMEM;
|
||||
}else{
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
}else{
|
||||
mosquitto__free(mosq->tls_version);
|
||||
mosq->tls_version = mosquitto__strdup("tlsv1.2");
|
||||
if(!mosq->tls_version) return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
if(ciphers){
|
||||
mosquitto__free(mosq->tls_ciphers);
|
||||
mosq->tls_ciphers = mosquitto__strdup(ciphers);
|
||||
if(!mosq->tls_ciphers) return MOSQ_ERR_NOMEM;
|
||||
}else{
|
||||
mosquitto__free(mosq->tls_ciphers);
|
||||
mosq->tls_ciphers = NULL;
|
||||
}
|
||||
|
||||
@ -286,6 +292,11 @@ int mosquitto_string_option(struct mosquitto *mosq, enum mosq_opt_t option, cons
|
||||
#if defined(WITH_TLS) && !defined(OPENSSL_NO_ENGINE)
|
||||
mosquitto__free(mosq->tls_engine);
|
||||
if(value){
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
/* The "Dynamic" OpenSSL engine is not initialized by default but
|
||||
is required by ENGINE_by_id() to find dynamically loadable engines */
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_DYNAMIC, NULL);
|
||||
#endif
|
||||
eng = ENGINE_by_id(value);
|
||||
if(!eng){
|
||||
return MOSQ_ERR_INVAL;
|
||||
|
@ -152,6 +152,21 @@ int packet__queue(struct mosquitto *mosq, struct mosquitto__packet *packet)
|
||||
|
||||
packet->next = NULL;
|
||||
pthread_mutex_lock(&mosq->out_packet_mutex);
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
if(mosq->out_packet_count >= db.config->max_queued_messages){
|
||||
mosquitto__free(packet);
|
||||
if(mosq->is_dropping == false){
|
||||
mosq->is_dropping = true;
|
||||
log__printf(NULL, MOSQ_LOG_NOTICE,
|
||||
"Outgoing messages are being dropped for client %s.",
|
||||
mosq->id);
|
||||
}
|
||||
G_MSGS_DROPPED_INC();
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(mosq->out_packet){
|
||||
mosq->out_packet_last->next = packet;
|
||||
}else{
|
||||
@ -268,6 +283,8 @@ int packet__write(struct mosquitto *mosq)
|
||||
return MOSQ_ERR_CONN_LOST;
|
||||
case COMPAT_EINTR:
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
case EPROTO:
|
||||
return MOSQ_ERR_TLS;
|
||||
default:
|
||||
return MOSQ_ERR_ERRNO;
|
||||
}
|
||||
@ -376,7 +393,7 @@ 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) && state == mosq_cs_connected && (byte&0xF0) != CMD_CONNECT){
|
||||
if(!(mosq->bridge) && state == mosq_cs_new && (byte&0xF0) != CMD_CONNECT){
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
#endif
|
||||
|
@ -141,7 +141,9 @@ static int property__read(struct mosquitto__packet *packet, uint32_t *len, mosqu
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef WITH_BROKER
|
||||
log__printf(NULL, MOSQ_LOG_DEBUG, "Unsupported property type: %d", property_identifier);
|
||||
#endif
|
||||
return MOSQ_ERR_MALFORMED_PACKET;
|
||||
}
|
||||
|
||||
@ -415,7 +417,9 @@ static int property__write(struct mosquitto__packet *packet, const mosquitto_pro
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef WITH_BROKER
|
||||
log__printf(NULL, MOSQ_LOG_DEBUG, "Unsupported property type: %d", property->identifier);
|
||||
#endif
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
|
||||
@ -1248,7 +1252,7 @@ int mosquitto_property_copy_all(mosquitto_property **dest, const mosquitto_prope
|
||||
case MQTT_PROP_SERVER_REFERENCE:
|
||||
case MQTT_PROP_REASON_STRING:
|
||||
pnew->value.s.len = src->value.s.len;
|
||||
pnew->value.s.v = strdup(src->value.s.v);
|
||||
pnew->value.s.v = src->value.s.v ? strdup(src->value.s.v) : (char*)calloc(1,1);
|
||||
if(!pnew->value.s.v){
|
||||
mosquitto_property_free_all(dest);
|
||||
return MOSQ_ERR_NOMEM;
|
||||
@ -1268,14 +1272,14 @@ int mosquitto_property_copy_all(mosquitto_property **dest, const mosquitto_prope
|
||||
|
||||
case MQTT_PROP_USER_PROPERTY:
|
||||
pnew->value.s.len = src->value.s.len;
|
||||
pnew->value.s.v = strdup(src->value.s.v);
|
||||
pnew->value.s.v = src->value.s.v ? strdup(src->value.s.v) : (char*)calloc(1,1);
|
||||
if(!pnew->value.s.v){
|
||||
mosquitto_property_free_all(dest);
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
|
||||
pnew->name.len = src->name.len;
|
||||
pnew->name.v = strdup(src->name.v);
|
||||
pnew->name.v = src->name.v ? strdup(src->name.v) : (char*)calloc(1,1);
|
||||
if(!pnew->name.v){
|
||||
mosquitto_property_free_all(dest);
|
||||
return MOSQ_ERR_NOMEM;
|
||||
|
@ -177,7 +177,7 @@ int send__real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic,
|
||||
#ifdef WITH_BROKER
|
||||
log__printf(NULL, MOSQ_LOG_NOTICE, "Dropping too large outgoing PUBLISH for %s (%d bytes)", SAFE_PRINT(mosq->id), packetlen);
|
||||
#else
|
||||
log__printf(NULL, MOSQ_LOG_NOTICE, "Dropping too large outgoing PUBLISH (%d bytes)", packetlen);
|
||||
log__printf(mosq, MOSQ_LOG_NOTICE, "Dropping too large outgoing PUBLISH (%d bytes)", packetlen);
|
||||
#endif
|
||||
return MOSQ_ERR_OVERSIZE_PACKET;
|
||||
}
|
||||
|
@ -75,6 +75,10 @@ const char *mosquitto_strerror(int mosq_errno)
|
||||
return "Proxy error.";
|
||||
case MOSQ_ERR_MALFORMED_UTF8:
|
||||
return "Malformed UTF-8";
|
||||
case MOSQ_ERR_KEEPALIVE:
|
||||
return "Keepalive exceeded";
|
||||
case MOSQ_ERR_LOOKUP:
|
||||
return "DNS Lookup failed";
|
||||
case MOSQ_ERR_DUPLICATE_PROPERTY:
|
||||
return "Duplicate property in property list";
|
||||
case MOSQ_ERR_TLS_HANDSHAKE:
|
||||
|
@ -43,7 +43,11 @@ time_t mosquitto_time(void)
|
||||
#elif _POSIX_TIMERS>0 && defined(_POSIX_MONOTONIC_CLOCK)
|
||||
struct timespec tp;
|
||||
|
||||
#ifdef CLOCK_BOOTTIME
|
||||
clock_gettime(CLOCK_BOOTTIME, &tp);
|
||||
#else
|
||||
clock_gettime(CLOCK_MONOTONIC, &tp);
|
||||
#endif
|
||||
return tp.tv_sec;
|
||||
#elif defined(__APPLE__)
|
||||
static mach_timebase_info_data_t tb;
|
||||
|
@ -105,6 +105,17 @@ static int mosquitto__cmp_hostname_wildcard(char *certname, const char *hostname
|
||||
break;
|
||||
}
|
||||
}
|
||||
len = strlen(hostname);
|
||||
int dotcount = 0;
|
||||
for(i=0; i<len-1; i++){
|
||||
if(hostname[i] == '.'){
|
||||
dotcount++;
|
||||
}
|
||||
}
|
||||
if(dotcount < 1){
|
||||
/* Exclude e.g. *.com, allow e.g. *.example.com */
|
||||
return 1;
|
||||
}
|
||||
return strcasecmp(certname, hostname);
|
||||
}else{
|
||||
return strcasecmp(certname, hostname);
|
||||
|
@ -4,44 +4,45 @@
|
||||
# could not be found, then the man pages will not be built or installed -
|
||||
# because the install is optional.
|
||||
|
||||
if(NOT WIN32)
|
||||
find_program(XSLTPROC xsltproc OPTIONAL)
|
||||
if(XSLTPROC)
|
||||
function(compile_manpage page)
|
||||
add_custom_command(OUTPUT ${PROJECT_SOURCE_DIR}/man/${page}
|
||||
COMMAND xsltproc ${PROJECT_SOURCE_DIR}/man/${page}.xml -o ${PROJECT_SOURCE_DIR}/man/
|
||||
MAIN_DEPENDENCY ${PROJECT_SOURCE_DIR}/man/${page}.xml)
|
||||
add_custom_target(${page} ALL DEPENDS ${PROJECT_SOURCE_DIR}/man/${page})
|
||||
endfunction()
|
||||
find_program(XSLTPROC xsltproc OPTIONAL)
|
||||
if(XSLTPROC)
|
||||
function(compile_manpage page)
|
||||
add_custom_command(OUTPUT ${PROJECT_SOURCE_DIR}/man/${page}
|
||||
COMMAND xsltproc ${PROJECT_SOURCE_DIR}/man/${page}.xml -o ${PROJECT_SOURCE_DIR}/man/
|
||||
MAIN_DEPENDENCY ${PROJECT_SOURCE_DIR}/man/${page}.xml)
|
||||
add_custom_target(${page} ALL DEPENDS ${PROJECT_SOURCE_DIR}/man/${page})
|
||||
endfunction()
|
||||
|
||||
compile_manpage("mosquitto_ctrl.1")
|
||||
compile_manpage("mosquitto_ctrl_dynsec.1")
|
||||
compile_manpage("mosquitto_passwd.1")
|
||||
compile_manpage("mosquitto_pub.1")
|
||||
compile_manpage("mosquitto_sub.1")
|
||||
compile_manpage("mosquitto_rr.1")
|
||||
compile_manpage("libmosquitto.3")
|
||||
compile_manpage("mosquitto.conf.5")
|
||||
compile_manpage("mosquitto-tls.7")
|
||||
compile_manpage("mqtt.7")
|
||||
compile_manpage("mosquitto.8")
|
||||
else()
|
||||
message(FATAL_ERROR "xsltproc not found: manpages cannot be built")
|
||||
endif()
|
||||
compile_manpage("mosquitto_ctrl.1")
|
||||
compile_manpage("mosquitto_ctrl_dynsec.1")
|
||||
compile_manpage("mosquitto_passwd.1")
|
||||
compile_manpage("mosquitto_pub.1")
|
||||
compile_manpage("mosquitto_sub.1")
|
||||
compile_manpage("mosquitto_rr.1")
|
||||
compile_manpage("libmosquitto.3")
|
||||
compile_manpage("mosquitto.conf.5")
|
||||
compile_manpage("mosquitto-tls.7")
|
||||
compile_manpage("mqtt.7")
|
||||
compile_manpage("mosquitto.8")
|
||||
|
||||
install(FILES
|
||||
mosquitto_ctrl.1
|
||||
mosquitto_ctrl_dynsec.1
|
||||
mosquitto_passwd.1
|
||||
mosquitto_pub.1
|
||||
mosquitto_sub.1
|
||||
mosquitto_rr.1
|
||||
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1
|
||||
OPTIONAL)
|
||||
|
||||
install(FILES libmosquitto.3 DESTINATION ${CMAKE_INSTALL_MANDIR}/man3 OPTIONAL)
|
||||
install(FILES mosquitto.conf.5 DESTINATION ${CMAKE_INSTALL_MANDIR}/man5 OPTIONAL)
|
||||
install(FILES mosquitto-tls.7 mqtt.7 DESTINATION ${CMAKE_INSTALL_MANDIR}/man7 OPTIONAL)
|
||||
install(FILES mosquitto.8 DESTINATION ${CMAKE_INSTALL_MANDIR}/man8 OPTIONAL)
|
||||
|
||||
elseif(WIN32)
|
||||
message(WARNING "xsltproc not found: manpages cannot be built")
|
||||
else()
|
||||
message(FATAL_ERROR "xsltproc not found: manpages cannot be built")
|
||||
endif()
|
||||
|
||||
install(FILES
|
||||
mosquitto_ctrl.1
|
||||
mosquitto_ctrl_dynsec.1
|
||||
mosquitto_passwd.1
|
||||
mosquitto_pub.1
|
||||
mosquitto_sub.1
|
||||
mosquitto_rr.1
|
||||
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1
|
||||
OPTIONAL)
|
||||
|
||||
install(FILES libmosquitto.3 DESTINATION ${CMAKE_INSTALL_MANDIR}/man3 OPTIONAL)
|
||||
install(FILES mosquitto.conf.5 DESTINATION ${CMAKE_INSTALL_MANDIR}/man5 OPTIONAL)
|
||||
install(FILES mosquitto-tls.7 mqtt.7 DESTINATION ${CMAKE_INSTALL_MANDIR}/man7 OPTIONAL)
|
||||
install(FILES mosquitto.8 DESTINATION ${CMAKE_INSTALL_MANDIR}/man8 OPTIONAL)
|
||||
|
@ -47,7 +47,7 @@
|
||||
<title>Server</title>
|
||||
<para>Generate a server key.</para>
|
||||
<itemizedlist mark="circle">
|
||||
<listitem><para>openssl genrsa -des3 -out server.key 2048</para></listitem>
|
||||
<listitem><para>openssl genrsa -aes256 -out server.key 2048</para></listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>Generate a server key without encryption.</para>
|
||||
@ -71,7 +71,7 @@
|
||||
<title>Client</title>
|
||||
<para>Generate a client key.</para>
|
||||
<itemizedlist mark="circle">
|
||||
<listitem><para>openssl genrsa -des3 -out client.key 2048</para></listitem>
|
||||
<listitem><para>openssl genrsa -aes256 -out client.key 2048</para></listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>Generate a certificate signing request to send to the CA.</para>
|
||||
|
@ -1391,9 +1391,12 @@ openssl dhparam -out dhparam.pem 2048</programlisting>
|
||||
<term><option>keyfile</option> <replaceable>file path</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Path to the PEM encoded server key. This
|
||||
option and <option>certfile</option> must be present
|
||||
to enable certificate based TLS encryption.
|
||||
If <option>tls_keyform</option> equals "pem" this is the
|
||||
path to the PEM encoded server key. This option
|
||||
and <option>certfile</option> must be present
|
||||
to enable certificate based TLS encryption. If
|
||||
<option>tls_keyform</option> is "engine" this represents
|
||||
the engine handle of the private key.
|
||||
</para>
|
||||
<para>
|
||||
The private key pointed to by this option will be
|
||||
@ -1458,7 +1461,7 @@ openssl dhparam -out dhparam.pem 2048</programlisting>
|
||||
<replaceable>tlsv1.3</replaceable>,
|
||||
<replaceable>tlsv1.2</replaceable> and
|
||||
<replaceable>tlsv1.1</replaceable>. If left unset,
|
||||
the default of allowing TLS v1.3 and v1.2.</para>
|
||||
the default allows TLS v1.3 and v1.2.</para>
|
||||
<para>In Mosquitto version 1.6.x and earlier, this
|
||||
option set the only TLS protocol version that
|
||||
was allowed, rather than the minimum.</para>
|
||||
|
@ -639,6 +639,16 @@
|
||||
Defaults to <option>5</option>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-W</option></term>
|
||||
<listitem>
|
||||
<para>Provide a timeout as an integer number of seconds.
|
||||
mosquitto_sub will stop processing messages and
|
||||
disconnect after this number of seconds has
|
||||
passed. The timeout starts just after the client has
|
||||
connected to the broker.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--will-payload</option></term>
|
||||
<listitem>
|
||||
|
@ -938,7 +938,6 @@ mosquitto_sub -t 'bbc/#' -T bbc/bbc1 --remove-retained</programlisting>
|
||||
<para>If the payload is not valid JSON, then the error message "Error: Message payload is not valid JSON on topic
|
||||
<topic>" will be printed to stderr.</para></listitem>
|
||||
|
||||
<listitem><para><option>%I</option> ISO-8601 format date and time, e.g. 2016-08-10T09:47:38+0100</para></listitem>
|
||||
<listitem><para><option>%U</option> Unix timestamp with nanoseconds, e.g. 1470818943.786368637</para></listitem>
|
||||
</itemizedlist>
|
||||
</refsect2>
|
||||
|
@ -17,17 +17,19 @@ MY_DOMAIN=example.com
|
||||
# Set the directory that the certificates will be copied to.
|
||||
CERTIFICATE_DIR=/etc/mosquitto/certs
|
||||
|
||||
if [ "${RENEWED_DOMAINS}" = "${MY_DOMAIN}" ]; then
|
||||
# Copy new certificate to Mosquitto directory
|
||||
cp ${RENEWED_LINEAGE}/fullchain.pem ${CERTIFICATE_DIR}/server.pem
|
||||
cp ${RENEWED_LINEAGE}/privkey.pem ${CERTIFICATE_DIR}/server.key
|
||||
for D in ${RENEWED_DOMAINS}; do
|
||||
if [ "${D}" = "${MY_DOMAIN}" ]; then
|
||||
# Copy new certificate to Mosquitto directory
|
||||
cp ${RENEWED_LINEAGE}/fullchain.pem ${CERTIFICATE_DIR}/server.pem
|
||||
cp ${RENEWED_LINEAGE}/privkey.pem ${CERTIFICATE_DIR}/server.key
|
||||
|
||||
# Set ownership to Mosquitto
|
||||
chown mosquitto: ${CERTIFICATE_DIR}/server.pem ${CERTIFICATE_DIR}/server.key
|
||||
# Set ownership to Mosquitto
|
||||
chown mosquitto: ${CERTIFICATE_DIR}/server.pem ${CERTIFICATE_DIR}/server.key
|
||||
|
||||
# Ensure permissions are restrictive
|
||||
chmod 0600 ${CERTIFICATE_DIR}/server.pem ${CERTIFICATE_DIR}/server.key
|
||||
# Ensure permissions are restrictive
|
||||
chmod 0600 ${CERTIFICATE_DIR}/server.pem ${CERTIFICATE_DIR}/server.key
|
||||
|
||||
# Tell Mosquitto to reload certificates and configuration
|
||||
pkill -HUP -x mosquitto
|
||||
fi
|
||||
# Tell Mosquitto to reload certificates and configuration
|
||||
pkill -HUP -x mosquitto
|
||||
fi
|
||||
done
|
||||
|
@ -106,5 +106,5 @@ int mosquitto_plugin_cleanup(void *user_data, struct mosquitto_opt *opts, int op
|
||||
UNUSED(opts);
|
||||
UNUSED(opt_count);
|
||||
|
||||
return mosquitto_callback_unregister(mosq_pid, MOSQ_EVT_MESSAGE, basic_auth_callback, NULL);
|
||||
return mosquitto_callback_unregister(mosq_pid, MOSQ_EVT_BASIC_AUTH, basic_auth_callback, NULL);
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ Command:
|
||||
{
|
||||
"commands":[
|
||||
{
|
||||
"command": "getDefaultACLAccess",
|
||||
"command": "getDefaultACLAccess"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -244,7 +244,7 @@ Command:
|
||||
|
||||
mosquitto_ctrl example:
|
||||
```
|
||||
mosquitto_ctrl dynsec setClientPassword username password
|
||||
mosquitto_ctrl dynsec setClientId username clientId
|
||||
```
|
||||
|
||||
## Set Client Password
|
||||
@ -523,7 +523,7 @@ Command:
|
||||
{
|
||||
"commands":[
|
||||
{
|
||||
"command": "getAnonymousGroup",
|
||||
"command": "getAnonymousGroup"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -163,9 +163,7 @@ static int memcmp_const(const void *a, const void *b, size_t len)
|
||||
if(!a || !b) return 1;
|
||||
|
||||
for(i=0; i<len; i++){
|
||||
if( ((char *)a)[i] != ((char *)b)[i] ){
|
||||
rc = 1;
|
||||
}
|
||||
rc |= ((char *)a)[i] ^ ((char *)b)[i];
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -106,14 +106,12 @@ void dynsec_clients__cleanup(void)
|
||||
|
||||
int dynsec_clients__config_load(cJSON *tree)
|
||||
{
|
||||
cJSON *j_clients, *j_client, *jtmp, *j_roles, *j_role;
|
||||
cJSON *j_salt, *j_password, *j_iterations;
|
||||
cJSON *j_clients, *j_client, *j_roles, *j_role;
|
||||
struct dynsec__client *client;
|
||||
struct dynsec__role *role;
|
||||
unsigned char *buf;
|
||||
int buf_len;
|
||||
int priority;
|
||||
int iterations;
|
||||
|
||||
j_clients = cJSON_GetObjectItem(tree, "clients");
|
||||
if(j_clients == NULL){
|
||||
@ -126,47 +124,46 @@ int dynsec_clients__config_load(cJSON *tree)
|
||||
|
||||
cJSON_ArrayForEach(j_client, j_clients){
|
||||
if(cJSON_IsObject(j_client) == true){
|
||||
/* Username */
|
||||
char *username;
|
||||
json_get_string(j_client, "username", &username, false);
|
||||
if(!username){
|
||||
continue;
|
||||
}
|
||||
|
||||
client = dynsec_clients__find(username);
|
||||
if(client){
|
||||
continue;
|
||||
}
|
||||
|
||||
client = mosquitto_calloc(1, sizeof(struct dynsec__client));
|
||||
if(client == NULL){
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
|
||||
/* Username */
|
||||
jtmp = cJSON_GetObjectItem(j_client, "username");
|
||||
if(jtmp == NULL || !cJSON_IsString(jtmp)){
|
||||
mosquitto_free(client);
|
||||
continue;
|
||||
}
|
||||
client->username = mosquitto_strdup(jtmp->valuestring);
|
||||
|
||||
client->username = mosquitto_strdup(username);
|
||||
if(client->username == NULL){
|
||||
mosquitto_free(client);
|
||||
continue;
|
||||
}
|
||||
|
||||
jtmp = cJSON_GetObjectItem(j_client, "disabled");
|
||||
if(jtmp && cJSON_IsBool(jtmp)){
|
||||
client->disabled = cJSON_IsTrue(jtmp);
|
||||
bool disabled;
|
||||
if(json_get_bool(j_client, "disabled", &disabled, false, false) == MOSQ_ERR_SUCCESS){
|
||||
client->disabled = disabled;
|
||||
}
|
||||
|
||||
/* Salt */
|
||||
j_salt = cJSON_GetObjectItem(j_client, "salt");
|
||||
j_password = cJSON_GetObjectItem(j_client, "password");
|
||||
j_iterations = cJSON_GetObjectItem(j_client, "iterations");
|
||||
char *salt, *password;
|
||||
int iterations;
|
||||
json_get_string(j_client, "salt", &salt, false);
|
||||
json_get_string(j_client, "password", &password, false);
|
||||
json_get_int(j_client, "iterations", &iterations, false, -1);
|
||||
|
||||
if(j_salt && cJSON_IsString(j_salt)
|
||||
&& j_password && cJSON_IsString(j_password)
|
||||
&& j_iterations && cJSON_IsNumber(j_iterations)){
|
||||
if(salt && password && iterations > 0){
|
||||
client->pw.iterations = iterations;
|
||||
|
||||
iterations = (int)j_iterations->valuedouble;
|
||||
if(iterations < 1){
|
||||
mosquitto_free(client->username);
|
||||
mosquitto_free(client);
|
||||
continue;
|
||||
}else{
|
||||
client->pw.iterations = iterations;
|
||||
}
|
||||
|
||||
if(dynsec_auth__base64_decode(j_salt->valuestring, &buf, &buf_len) != MOSQ_ERR_SUCCESS
|
||||
if(dynsec_auth__base64_decode(salt, &buf, &buf_len) != MOSQ_ERR_SUCCESS
|
||||
|| buf_len != sizeof(client->pw.salt)){
|
||||
|
||||
mosquitto_free(client->username);
|
||||
@ -176,7 +173,7 @@ int dynsec_clients__config_load(cJSON *tree)
|
||||
memcpy(client->pw.salt, buf, (size_t)buf_len);
|
||||
mosquitto_free(buf);
|
||||
|
||||
if(dynsec_auth__base64_decode(j_password->valuestring, &buf, &buf_len) != MOSQ_ERR_SUCCESS
|
||||
if(dynsec_auth__base64_decode(password, &buf, &buf_len) != MOSQ_ERR_SUCCESS
|
||||
|| buf_len != sizeof(client->pw.password_hash)){
|
||||
|
||||
mosquitto_free(client->username);
|
||||
@ -191,9 +188,10 @@ int dynsec_clients__config_load(cJSON *tree)
|
||||
}
|
||||
|
||||
/* Client id */
|
||||
jtmp = cJSON_GetObjectItem(j_client, "clientid");
|
||||
if(jtmp != NULL && cJSON_IsString(jtmp)){
|
||||
client->clientid = mosquitto_strdup(jtmp->valuestring);
|
||||
char *clientid;
|
||||
json_get_string(j_client, "clientid", &clientid, false);
|
||||
if(clientid){
|
||||
client->clientid = mosquitto_strdup(clientid);
|
||||
if(client->clientid == NULL){
|
||||
mosquitto_free(client->username);
|
||||
mosquitto_free(client);
|
||||
@ -202,9 +200,10 @@ int dynsec_clients__config_load(cJSON *tree)
|
||||
}
|
||||
|
||||
/* Text name */
|
||||
jtmp = cJSON_GetObjectItem(j_client, "textname");
|
||||
if(jtmp != NULL && cJSON_IsString(jtmp)){
|
||||
client->text_name = mosquitto_strdup(jtmp->valuestring);
|
||||
char *textname;
|
||||
json_get_string(j_client, "textname", &textname, false);
|
||||
if(textname){
|
||||
client->text_name = mosquitto_strdup(textname);
|
||||
if(client->text_name == NULL){
|
||||
mosquitto_free(client->clientid);
|
||||
mosquitto_free(client->username);
|
||||
@ -214,9 +213,10 @@ int dynsec_clients__config_load(cJSON *tree)
|
||||
}
|
||||
|
||||
/* Text description */
|
||||
jtmp = cJSON_GetObjectItem(j_client, "textdescription");
|
||||
if(jtmp != NULL && cJSON_IsString(jtmp)){
|
||||
client->text_description = mosquitto_strdup(jtmp->valuestring);
|
||||
char *textdescription;
|
||||
json_get_string(j_client, "textdescription", &textdescription, false);
|
||||
if(textdescription){
|
||||
client->text_description = mosquitto_strdup(textdescription);
|
||||
if(client->text_description == NULL){
|
||||
mosquitto_free(client->text_name);
|
||||
mosquitto_free(client->clientid);
|
||||
@ -231,10 +231,11 @@ int dynsec_clients__config_load(cJSON *tree)
|
||||
if(j_roles && cJSON_IsArray(j_roles)){
|
||||
cJSON_ArrayForEach(j_role, j_roles){
|
||||
if(cJSON_IsObject(j_role)){
|
||||
jtmp = cJSON_GetObjectItem(j_role, "rolename");
|
||||
if(jtmp && cJSON_IsString(jtmp)){
|
||||
char *rolename;
|
||||
json_get_string(j_role, "rolename", &rolename, false);
|
||||
if(rolename){
|
||||
json_get_int(j_role, "priority", &priority, true, -1);
|
||||
role = dynsec_roles__find(jtmp->valuestring);
|
||||
role = dynsec_roles__find(rolename);
|
||||
dynsec_rolelist__client_add(client, role, priority);
|
||||
}
|
||||
}
|
||||
@ -326,7 +327,7 @@ int dynsec_clients__process_create(cJSON *j_responses, struct mosquitto *context
|
||||
char *text_name, *text_description;
|
||||
struct dynsec__client *client;
|
||||
int rc;
|
||||
cJSON *j_groups, *j_group, *jtmp;
|
||||
cJSON *j_groups, *j_group;
|
||||
int priority;
|
||||
const char *admin_clientid, *admin_username;
|
||||
|
||||
@ -438,10 +439,11 @@ int dynsec_clients__process_create(cJSON *j_responses, struct mosquitto *context
|
||||
if(j_groups && cJSON_IsArray(j_groups)){
|
||||
cJSON_ArrayForEach(j_group, j_groups){
|
||||
if(cJSON_IsObject(j_group)){
|
||||
jtmp = cJSON_GetObjectItem(j_group, "groupname");
|
||||
if(jtmp && cJSON_IsString(jtmp)){
|
||||
char *groupname;
|
||||
json_get_string(j_group, "groupname", &groupname, false);
|
||||
if(groupname){
|
||||
json_get_int(j_group, "priority", &priority, true, -1);
|
||||
rc = dynsec_groups__add_client(username, jtmp->valuestring, priority, false);
|
||||
rc = dynsec_groups__add_client(username, groupname, priority, false);
|
||||
if(rc == ERR_GROUP_NOT_FOUND){
|
||||
dynsec__command_reply(j_responses, context, "createClient", "Group not found", correlation_data);
|
||||
client__free_item(client);
|
||||
@ -730,7 +732,7 @@ int dynsec_clients__process_modify(cJSON *j_responses, struct mosquitto *context
|
||||
char *str;
|
||||
int rc;
|
||||
int priority;
|
||||
cJSON *j_group, *j_groups, *jtmp;
|
||||
cJSON *j_group, *j_groups;
|
||||
const char *admin_clientid, *admin_username;
|
||||
|
||||
if(json_get_string(command, "username", &username, false) != MOSQ_ERR_SUCCESS){
|
||||
@ -812,9 +814,10 @@ int dynsec_clients__process_modify(cJSON *j_responses, struct mosquitto *context
|
||||
/* Iterate through list to check all groups are valid */
|
||||
cJSON_ArrayForEach(j_group, j_groups){
|
||||
if(cJSON_IsObject(j_group)){
|
||||
jtmp = cJSON_GetObjectItem(j_group, "groupname");
|
||||
if(jtmp && cJSON_IsString(jtmp)){
|
||||
group = dynsec_groups__find(jtmp->valuestring);
|
||||
char *groupname;
|
||||
json_get_string(j_group, "groupname", &groupname, false);
|
||||
if(groupname){
|
||||
group = dynsec_groups__find(groupname);
|
||||
if(group == NULL){
|
||||
dynsec__command_reply(j_responses, context, "modifyClient", "'groups' contains an object with a 'groupname' that does not exist", correlation_data);
|
||||
rc = MOSQ_ERR_INVAL;
|
||||
@ -831,10 +834,11 @@ int dynsec_clients__process_modify(cJSON *j_responses, struct mosquitto *context
|
||||
dynsec__remove_client_from_all_groups(username);
|
||||
cJSON_ArrayForEach(j_group, j_groups){
|
||||
if(cJSON_IsObject(j_group)){
|
||||
jtmp = cJSON_GetObjectItem(j_group, "groupname");
|
||||
if(jtmp && cJSON_IsString(jtmp)){
|
||||
char *groupname;
|
||||
json_get_string(j_group, "groupname", &groupname, false);
|
||||
if(groupname){
|
||||
json_get_int(j_group, "priority", &priority, true, -1);
|
||||
dynsec_groups__add_client(username, jtmp->valuestring, priority, false);
|
||||
dynsec_groups__add_client(username, groupname, priority, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -195,12 +195,12 @@ void dynsec_groups__cleanup(void)
|
||||
int dynsec_groups__config_load(cJSON *tree)
|
||||
{
|
||||
cJSON *j_groups, *j_group;
|
||||
cJSON *j_clientlist, *j_client, *j_username;
|
||||
cJSON *j_roles, *j_role, *j_rolename;
|
||||
cJSON *j_clientlist, *j_client;
|
||||
cJSON *j_roles, *j_role;
|
||||
|
||||
struct dynsec__group *group;
|
||||
struct dynsec__role *role;
|
||||
char *str;
|
||||
char *groupname;
|
||||
int priority;
|
||||
|
||||
j_groups = cJSON_GetObjectItem(tree, "groups");
|
||||
@ -214,26 +214,31 @@ int dynsec_groups__config_load(cJSON *tree)
|
||||
|
||||
cJSON_ArrayForEach(j_group, j_groups){
|
||||
if(cJSON_IsObject(j_group) == true){
|
||||
/* Group name */
|
||||
if(json_get_string(j_group, "groupname", &groupname, false) != MOSQ_ERR_SUCCESS){
|
||||
continue;
|
||||
}
|
||||
group = dynsec_groups__find(groupname);
|
||||
if(group){
|
||||
continue;
|
||||
}
|
||||
|
||||
group = mosquitto_calloc(1, sizeof(struct dynsec__group));
|
||||
if(group == NULL){
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
|
||||
/* Group name */
|
||||
if(json_get_string(j_group, "groupname", &str, false) != MOSQ_ERR_SUCCESS){
|
||||
mosquitto_free(group);
|
||||
continue;
|
||||
}
|
||||
group->groupname = strdup(str);
|
||||
group->groupname = strdup(groupname);
|
||||
if(group->groupname == NULL){
|
||||
mosquitto_free(group);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Text name */
|
||||
if(json_get_string(j_group, "textname", &str, false) == MOSQ_ERR_SUCCESS){
|
||||
if(str){
|
||||
group->text_name = strdup(str);
|
||||
char *textname;
|
||||
if(json_get_string(j_group, "textname", &textname, false) == MOSQ_ERR_SUCCESS){
|
||||
if(textname){
|
||||
group->text_name = strdup(textname);
|
||||
if(group->text_name == NULL){
|
||||
mosquitto_free(group->groupname);
|
||||
mosquitto_free(group);
|
||||
@ -243,9 +248,10 @@ int dynsec_groups__config_load(cJSON *tree)
|
||||
}
|
||||
|
||||
/* Text description */
|
||||
if(json_get_string(j_group, "textdescription", &str, false) == MOSQ_ERR_SUCCESS){
|
||||
if(str){
|
||||
group->text_description = strdup(str);
|
||||
char *textdescription;
|
||||
if(json_get_string(j_group, "textdescription", &textdescription, false) == MOSQ_ERR_SUCCESS){
|
||||
if(textdescription){
|
||||
group->text_description = strdup(textdescription);
|
||||
if(group->text_description == NULL){
|
||||
mosquitto_free(group->text_name);
|
||||
mosquitto_free(group->groupname);
|
||||
@ -260,10 +266,11 @@ int dynsec_groups__config_load(cJSON *tree)
|
||||
if(j_roles && cJSON_IsArray(j_roles)){
|
||||
cJSON_ArrayForEach(j_role, j_roles){
|
||||
if(cJSON_IsObject(j_role)){
|
||||
j_rolename = cJSON_GetObjectItem(j_role, "rolename");
|
||||
if(j_rolename && cJSON_IsString(j_rolename)){
|
||||
char *rolename;
|
||||
json_get_string(j_role, "rolename", &rolename, false);
|
||||
if(rolename){
|
||||
json_get_int(j_role, "priority", &priority, true, -1);
|
||||
role = dynsec_roles__find(j_rolename->valuestring);
|
||||
role = dynsec_roles__find(rolename);
|
||||
dynsec_rolelist__group_add(group, role, priority);
|
||||
}
|
||||
}
|
||||
@ -278,10 +285,11 @@ int dynsec_groups__config_load(cJSON *tree)
|
||||
if(j_clientlist && cJSON_IsArray(j_clientlist)){
|
||||
cJSON_ArrayForEach(j_client, j_clientlist){
|
||||
if(cJSON_IsObject(j_client)){
|
||||
j_username = cJSON_GetObjectItem(j_client, "username");
|
||||
if(j_username && cJSON_IsString(j_username)){
|
||||
char *username;
|
||||
json_get_string(j_client, "username", &username, false);
|
||||
if(username){
|
||||
json_get_int(j_client, "priority", &priority, true, -1);
|
||||
dynsec_groups__add_client(j_username->valuestring, group->groupname, priority, false);
|
||||
dynsec_groups__add_client(username, group->groupname, priority, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -290,9 +298,9 @@ int dynsec_groups__config_load(cJSON *tree)
|
||||
}
|
||||
HASH_SORT(local_groups, group_cmp);
|
||||
|
||||
j_group = cJSON_GetObjectItem(tree, "anonymousGroup");
|
||||
if(j_group && cJSON_IsString(j_group)){
|
||||
dynsec_anonymous_group = dynsec_groups__find(j_group->valuestring);
|
||||
json_get_string(tree, "anonymousGroup", &groupname, false);
|
||||
if(groupname){
|
||||
dynsec_anonymous_group = dynsec_groups__find(groupname);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -922,10 +930,12 @@ int dynsec_groups__process_modify(cJSON *j_responses, struct mosquitto *context,
|
||||
struct dynsec__group *group = NULL;
|
||||
struct dynsec__rolelist *rolelist = NULL;
|
||||
bool have_text_name = false, have_text_description = false, have_rolelist = false;
|
||||
char *str;
|
||||
int rc;
|
||||
int priority;
|
||||
cJSON *j_client, *j_clients, *jtmp;
|
||||
cJSON *j_client, *j_clients;
|
||||
char *username;
|
||||
char *textname;
|
||||
char *textdescription;
|
||||
const char *admin_clientid, *admin_username;
|
||||
|
||||
if(json_get_string(command, "groupname", &groupname, false) != MOSQ_ERR_SUCCESS){
|
||||
@ -943,9 +953,9 @@ int dynsec_groups__process_modify(cJSON *j_responses, struct mosquitto *context,
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
|
||||
if(json_get_string(command, "textname", &str, false) == MOSQ_ERR_SUCCESS){
|
||||
if(json_get_string(command, "textname", &textname, false) == MOSQ_ERR_SUCCESS){
|
||||
have_text_name = true;
|
||||
text_name = mosquitto_strdup(str);
|
||||
text_name = mosquitto_strdup(textname);
|
||||
if(text_name == NULL){
|
||||
dynsec__command_reply(j_responses, context, "modifyGroup", "Internal error", correlation_data);
|
||||
rc = MOSQ_ERR_NOMEM;
|
||||
@ -953,9 +963,9 @@ int dynsec_groups__process_modify(cJSON *j_responses, struct mosquitto *context,
|
||||
}
|
||||
}
|
||||
|
||||
if(json_get_string(command, "textdescription", &str, false) == MOSQ_ERR_SUCCESS){
|
||||
if(json_get_string(command, "textdescription", &textdescription, false) == MOSQ_ERR_SUCCESS){
|
||||
have_text_description = true;
|
||||
text_description = mosquitto_strdup(str);
|
||||
text_description = mosquitto_strdup(textdescription);
|
||||
if(text_description == NULL){
|
||||
dynsec__command_reply(j_responses, context, "modifyGroup", "Internal error", correlation_data);
|
||||
rc = MOSQ_ERR_NOMEM;
|
||||
@ -989,9 +999,9 @@ int dynsec_groups__process_modify(cJSON *j_responses, struct mosquitto *context,
|
||||
/* Iterate over array to check clients are valid before proceeding */
|
||||
cJSON_ArrayForEach(j_client, j_clients){
|
||||
if(cJSON_IsObject(j_client)){
|
||||
jtmp = cJSON_GetObjectItem(j_client, "username");
|
||||
if(jtmp && cJSON_IsString(jtmp)){
|
||||
client = dynsec_clients__find(jtmp->valuestring);
|
||||
json_get_string(j_client, "username", &username, false);
|
||||
if(username){
|
||||
client = dynsec_clients__find(username);
|
||||
if(client == NULL){
|
||||
dynsec__command_reply(j_responses, context, "modifyGroup", "'clients' contains an object with a 'username' that does not exist", correlation_data);
|
||||
rc = MOSQ_ERR_INVAL;
|
||||
@ -1012,10 +1022,10 @@ int dynsec_groups__process_modify(cJSON *j_responses, struct mosquitto *context,
|
||||
/* Now we can add the new clients to the group */
|
||||
cJSON_ArrayForEach(j_client, j_clients){
|
||||
if(cJSON_IsObject(j_client)){
|
||||
jtmp = cJSON_GetObjectItem(j_client, "username");
|
||||
if(jtmp && cJSON_IsString(jtmp)){
|
||||
json_get_string(j_client, "username", &username, false);
|
||||
if(username){
|
||||
json_get_int(j_client, "priority", &priority, true, -1);
|
||||
dynsec_groups__add_client(jtmp->valuestring, groupname, priority, false);
|
||||
dynsec_groups__add_client(username, groupname, priority, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,190 @@ static mosquitto_plugin_id_t *plg_id = NULL;
|
||||
static char *config_file = NULL;
|
||||
struct dynsec__acl_default_access default_access = {false, false, false, false};
|
||||
|
||||
#ifdef WIN32
|
||||
# include <winsock2.h>
|
||||
# include <aclapi.h>
|
||||
# include <io.h>
|
||||
# include <lmcons.h>
|
||||
# include <fcntl.h>
|
||||
# define PATH_MAX MAX_PATH
|
||||
#else
|
||||
# include <sys/stat.h>
|
||||
# include <pwd.h>
|
||||
# include <grp.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
/* Temporary - remove in 2.1 */
|
||||
FILE *mosquitto__fopen(const char *path, const char *mode, bool restrict_read)
|
||||
{
|
||||
#ifdef WIN32
|
||||
char buf[4096];
|
||||
int rc;
|
||||
int flags = 0;
|
||||
|
||||
rc = ExpandEnvironmentStringsA(path, buf, 4096);
|
||||
if(rc == 0 || rc > 4096){
|
||||
return NULL;
|
||||
}else{
|
||||
if (restrict_read) {
|
||||
HANDLE hfile;
|
||||
SECURITY_ATTRIBUTES sec;
|
||||
EXPLICIT_ACCESS_A ea;
|
||||
PACL pacl = NULL;
|
||||
char username[UNLEN + 1];
|
||||
DWORD ulen = UNLEN;
|
||||
SECURITY_DESCRIPTOR sd;
|
||||
DWORD dwCreationDisposition;
|
||||
int fd;
|
||||
FILE *fptr;
|
||||
|
||||
switch(mode[0]){
|
||||
case 'a':
|
||||
dwCreationDisposition = OPEN_ALWAYS;
|
||||
flags = _O_APPEND;
|
||||
break;
|
||||
case 'r':
|
||||
dwCreationDisposition = OPEN_EXISTING;
|
||||
flags = _O_RDONLY;
|
||||
break;
|
||||
case 'w':
|
||||
dwCreationDisposition = CREATE_ALWAYS;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GetUserNameA(username, &ulen);
|
||||
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
|
||||
return NULL;
|
||||
}
|
||||
BuildExplicitAccessWithNameA(&ea, username, GENERIC_ALL, SET_ACCESS, NO_INHERITANCE);
|
||||
if (SetEntriesInAclA(1, &ea, NULL, &pacl) != ERROR_SUCCESS) {
|
||||
return NULL;
|
||||
}
|
||||
if (!SetSecurityDescriptorDacl(&sd, TRUE, pacl, FALSE)) {
|
||||
LocalFree(pacl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(&sec, 0, sizeof(sec));
|
||||
sec.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
sec.bInheritHandle = FALSE;
|
||||
sec.lpSecurityDescriptor = &sd;
|
||||
|
||||
hfile = CreateFileA(buf, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
|
||||
&sec,
|
||||
dwCreationDisposition,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
|
||||
LocalFree(pacl);
|
||||
|
||||
fd = _open_osfhandle((intptr_t)hfile, flags);
|
||||
if (fd < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fptr = _fdopen(fd, mode);
|
||||
if (!fptr) {
|
||||
_close(fd);
|
||||
return NULL;
|
||||
}
|
||||
if(mode[0] == 'a'){
|
||||
fseek(fptr, 0, SEEK_END);
|
||||
}
|
||||
return fptr;
|
||||
|
||||
}else {
|
||||
return fopen(buf, mode);
|
||||
}
|
||||
}
|
||||
#else
|
||||
FILE *fptr;
|
||||
struct stat statbuf;
|
||||
|
||||
if (restrict_read) {
|
||||
mode_t old_mask;
|
||||
|
||||
old_mask = umask(0077);
|
||||
fptr = fopen(path, mode);
|
||||
umask(old_mask);
|
||||
}else{
|
||||
fptr = fopen(path, mode);
|
||||
}
|
||||
if(!fptr) return NULL;
|
||||
|
||||
if(fstat(fileno(fptr), &statbuf) < 0){
|
||||
fclose(fptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(restrict_read){
|
||||
if(statbuf.st_mode & S_IRWXO){
|
||||
#ifdef WITH_BROKER
|
||||
log__printf(NULL, MOSQ_LOG_WARNING,
|
||||
#else
|
||||
fprintf(stderr,
|
||||
#endif
|
||||
"Warning: File %s has world readable permissions. Future versions will refuse to load this file.",
|
||||
path);
|
||||
#if 0
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
if(statbuf.st_uid != getuid()){
|
||||
char buf[4096];
|
||||
struct passwd pw, *result;
|
||||
|
||||
getpwuid_r(getuid(), &pw, buf, sizeof(buf), &result);
|
||||
if(result){
|
||||
#ifdef WITH_BROKER
|
||||
log__printf(NULL, MOSQ_LOG_WARNING,
|
||||
#else
|
||||
fprintf(stderr,
|
||||
#endif
|
||||
"Warning: File %s owner is not %s. Future versions will refuse to load this file.",
|
||||
path, result->pw_name);
|
||||
}
|
||||
#if 0
|
||||
// Future version
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
if(statbuf.st_gid != getgid()){
|
||||
char buf[4096];
|
||||
struct group grp, *result;
|
||||
|
||||
getgrgid_r(getgid(), &grp, buf, sizeof(buf), &result);
|
||||
if(result){
|
||||
#ifdef WITH_BROKER
|
||||
log__printf(NULL, MOSQ_LOG_WARNING,
|
||||
#else
|
||||
fprintf(stderr,
|
||||
#endif
|
||||
"Warning: File %s group is not %s. Future versions will refuse to load this file.",
|
||||
path, result->gr_name);
|
||||
}
|
||||
#if 0
|
||||
// Future version
|
||||
return NULL
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!S_ISREG(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)){
|
||||
#ifdef WITH_BROKER
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error: %s is not a file.", path);
|
||||
#endif
|
||||
fclose(fptr);
|
||||
return NULL;
|
||||
}
|
||||
return fptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void dynsec__command_reply(cJSON *j_responses, struct mosquitto *context, const char *command, const char *error, const char *correlation_data)
|
||||
{
|
||||
cJSON *j_response;
|
||||
@ -137,8 +321,7 @@ static int dynsec_control_callback(int event, void *event_data, void *userdata)
|
||||
|
||||
static int dynsec__process_set_default_acl_access(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data)
|
||||
{
|
||||
cJSON *j_actions, *j_action, *j_acltype, *j_allow;
|
||||
bool allow;
|
||||
cJSON *j_actions, *j_action;
|
||||
const char *admin_clientid, *admin_username;
|
||||
|
||||
j_actions = cJSON_GetObjectItem(command, "acls");
|
||||
@ -151,24 +334,23 @@ static int dynsec__process_set_default_acl_access(cJSON *j_responses, struct mos
|
||||
admin_username = mosquitto_client_username(context);
|
||||
|
||||
cJSON_ArrayForEach(j_action, j_actions){
|
||||
j_acltype = cJSON_GetObjectItem(j_action, "acltype");
|
||||
j_allow = cJSON_GetObjectItem(j_action, "allow");
|
||||
if(j_acltype && cJSON_IsString(j_acltype)
|
||||
&& j_allow && cJSON_IsBool(j_allow)){
|
||||
char *acltype;
|
||||
bool allow;
|
||||
|
||||
allow = cJSON_IsTrue(j_allow);
|
||||
if(json_get_string(j_action, "acltype", &acltype, false) == MOSQ_ERR_SUCCESS
|
||||
&& json_get_bool(j_action, "allow", &allow, false, false) == MOSQ_ERR_SUCCESS){
|
||||
|
||||
if(!strcasecmp(j_acltype->valuestring, ACL_TYPE_PUB_C_SEND)){
|
||||
if(!strcasecmp(acltype, ACL_TYPE_PUB_C_SEND)){
|
||||
default_access.publish_c_send = allow;
|
||||
}else if(!strcasecmp(j_acltype->valuestring, ACL_TYPE_PUB_C_RECV)){
|
||||
}else if(!strcasecmp(acltype, ACL_TYPE_PUB_C_RECV)){
|
||||
default_access.publish_c_recv = allow;
|
||||
}else if(!strcasecmp(j_acltype->valuestring, ACL_TYPE_SUB_GENERIC)){
|
||||
}else if(!strcasecmp(acltype, ACL_TYPE_SUB_GENERIC)){
|
||||
default_access.subscribe = allow;
|
||||
}else if(!strcasecmp(j_acltype->valuestring, ACL_TYPE_UNSUB_GENERIC)){
|
||||
}else if(!strcasecmp(acltype, ACL_TYPE_UNSUB_GENERIC)){
|
||||
default_access.unsubscribe = allow;
|
||||
}
|
||||
mosquitto_log_printf(MOSQ_LOG_INFO, "dynsec: %s/%s | setDefaultACLAccess | acltype=%s | allow=%s",
|
||||
admin_clientid, admin_username, j_acltype->valuestring, allow?"true":"false");
|
||||
admin_clientid, admin_username, acltype, allow?"true":"false");
|
||||
}
|
||||
}
|
||||
|
||||
@ -292,37 +474,14 @@ int mosquitto_plugin_version(int supported_version_count, const int *supported_v
|
||||
|
||||
static int dynsec__general_config_load(cJSON *tree)
|
||||
{
|
||||
cJSON *j_default_access, *jtmp;
|
||||
cJSON *j_default_access;
|
||||
|
||||
j_default_access = cJSON_GetObjectItem(tree, "defaultACLAccess");
|
||||
if(j_default_access && cJSON_IsObject(j_default_access)){
|
||||
jtmp = cJSON_GetObjectItem(j_default_access, ACL_TYPE_PUB_C_SEND);
|
||||
if(jtmp && cJSON_IsBool(jtmp)){
|
||||
default_access.publish_c_send = cJSON_IsTrue(jtmp);
|
||||
}else{
|
||||
default_access.publish_c_send = false;
|
||||
}
|
||||
|
||||
jtmp = cJSON_GetObjectItem(j_default_access, ACL_TYPE_PUB_C_RECV);
|
||||
if(jtmp && cJSON_IsBool(jtmp)){
|
||||
default_access.publish_c_recv = cJSON_IsTrue(jtmp);
|
||||
}else{
|
||||
default_access.publish_c_recv = false;
|
||||
}
|
||||
|
||||
jtmp = cJSON_GetObjectItem(j_default_access, ACL_TYPE_SUB_GENERIC);
|
||||
if(jtmp && cJSON_IsBool(jtmp)){
|
||||
default_access.subscribe = cJSON_IsTrue(jtmp);
|
||||
}else{
|
||||
default_access.subscribe = false;
|
||||
}
|
||||
|
||||
jtmp = cJSON_GetObjectItem(j_default_access, ACL_TYPE_UNSUB_GENERIC);
|
||||
if(jtmp && cJSON_IsBool(jtmp)){
|
||||
default_access.unsubscribe = cJSON_IsTrue(jtmp);
|
||||
}else{
|
||||
default_access.unsubscribe = false;
|
||||
}
|
||||
json_get_bool(j_default_access, ACL_TYPE_PUB_C_SEND, &default_access.publish_c_send, true, false);
|
||||
json_get_bool(j_default_access, ACL_TYPE_PUB_C_RECV, &default_access.publish_c_recv, true, false);
|
||||
json_get_bool(j_default_access, ACL_TYPE_SUB_GENERIC, &default_access.subscribe, true, false);
|
||||
json_get_bool(j_default_access, ACL_TYPE_UNSUB_GENERIC, &default_access.unsubscribe, true, false);
|
||||
}
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
@ -359,7 +518,7 @@ static int dynsec__config_load(void)
|
||||
|
||||
/* Load from file */
|
||||
errno = 0;
|
||||
fptr = fopen(config_file, "rb");
|
||||
fptr = mosquitto__fopen(config_file, "rb", true);
|
||||
if(fptr == NULL){
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "Error loading Dynamic security plugin config: File is not readable - check permissions.\n");
|
||||
return MOSQ_ERR_ERRNO;
|
||||
@ -451,7 +610,7 @@ void dynsec__config_save(void)
|
||||
json_str_len = strlen(json_str);
|
||||
|
||||
/* Save to file */
|
||||
file_path_len = strlen(config_file) + 1;
|
||||
file_path_len = strlen(config_file) + strlen(".new") + 1;
|
||||
file_path = mosquitto_malloc(file_path_len);
|
||||
if(file_path == NULL){
|
||||
mosquitto_free(json_str);
|
||||
@ -460,7 +619,7 @@ void dynsec__config_save(void)
|
||||
}
|
||||
snprintf(file_path, file_path_len, "%s.new", config_file);
|
||||
|
||||
fptr = fopen(file_path, "wt");
|
||||
fptr = mosquitto__fopen(file_path, "wt", true);
|
||||
if(fptr == NULL){
|
||||
mosquitto_free(json_str);
|
||||
mosquitto_free(file_path);
|
||||
|
@ -164,7 +164,7 @@ int dynsec_rolelist__group_add(struct dynsec__group *group, struct dynsec__role
|
||||
|
||||
int dynsec_rolelist__load_from_json(cJSON *command, struct dynsec__rolelist **rolelist)
|
||||
{
|
||||
cJSON *j_roles, *j_role, *j_rolename;
|
||||
cJSON *j_roles, *j_role;
|
||||
int priority;
|
||||
struct dynsec__role *role;
|
||||
|
||||
@ -172,10 +172,11 @@ int dynsec_rolelist__load_from_json(cJSON *command, struct dynsec__rolelist **ro
|
||||
if(j_roles){
|
||||
if(cJSON_IsArray(j_roles)){
|
||||
cJSON_ArrayForEach(j_role, j_roles){
|
||||
j_rolename = cJSON_GetObjectItem(j_role, "rolename");
|
||||
if(j_rolename && cJSON_IsString(j_rolename)){
|
||||
char *rolename;
|
||||
json_get_string(j_role, "rolename", &rolename, false);
|
||||
if(rolename){
|
||||
json_get_int(j_role, "priority", &priority, true, -1);
|
||||
role = dynsec_roles__find(j_rolename->valuestring);
|
||||
role = dynsec_roles__find(rolename);
|
||||
if(role){
|
||||
dynsec_rolelist__add(rolelist, role, priority);
|
||||
}else{
|
||||
|
@ -215,14 +215,24 @@ static int insert_acl_cmp(struct dynsec__acl *a, struct dynsec__acl *b)
|
||||
|
||||
static int dynsec_roles__acl_load(cJSON *j_acls, const char *key, struct dynsec__acl **acllist)
|
||||
{
|
||||
cJSON *j_acl, *j_type, *jtmp;
|
||||
cJSON *j_acl;
|
||||
struct dynsec__acl *acl;
|
||||
|
||||
cJSON_ArrayForEach(j_acl, j_acls){
|
||||
j_type = cJSON_GetObjectItem(j_acl, "acltype");
|
||||
if(j_type == NULL || !cJSON_IsString(j_type) || strcasecmp(j_type->valuestring, key) != 0){
|
||||
char *acltype;
|
||||
char *topic;
|
||||
|
||||
json_get_string(j_acl, "acltype", &acltype, false);
|
||||
json_get_string(j_acl, "topic", &topic, false);
|
||||
|
||||
if(!acltype || strcasecmp(acltype, key) != 0 || !topic){
|
||||
continue;
|
||||
}
|
||||
HASH_FIND(hh, *acllist, topic, strlen(topic), acl);
|
||||
if(acl){
|
||||
continue;
|
||||
}
|
||||
|
||||
acl = mosquitto_calloc(1, sizeof(struct dynsec__acl));
|
||||
if(acl == NULL){
|
||||
return 1;
|
||||
@ -231,16 +241,12 @@ static int dynsec_roles__acl_load(cJSON *j_acls, const char *key, struct dynsec_
|
||||
json_get_int(j_acl, "priority", &acl->priority, true, 0);
|
||||
json_get_bool(j_acl, "allow", &acl->allow, true, false);
|
||||
|
||||
jtmp = cJSON_GetObjectItem(j_acl, "allow");
|
||||
if(jtmp && cJSON_IsBool(jtmp)){
|
||||
acl->allow = cJSON_IsTrue(jtmp);
|
||||
}
|
||||
|
||||
jtmp = cJSON_GetObjectItem(j_acl, "topic");
|
||||
if(jtmp && cJSON_IsString(jtmp)){
|
||||
acl->topic = mosquitto_strdup(jtmp->valuestring);
|
||||
bool allow;
|
||||
if(json_get_bool(j_acl, "allow", &allow, false, false) == MOSQ_ERR_SUCCESS){
|
||||
acl->allow = allow;
|
||||
}
|
||||
|
||||
acl->topic = mosquitto_strdup(topic);
|
||||
if(acl->topic == NULL){
|
||||
mosquitto_free(acl);
|
||||
continue;
|
||||
@ -255,7 +261,7 @@ static int dynsec_roles__acl_load(cJSON *j_acls, const char *key, struct dynsec_
|
||||
|
||||
int dynsec_roles__config_load(cJSON *tree)
|
||||
{
|
||||
cJSON *j_roles, *j_role, *jtmp, *j_acls;
|
||||
cJSON *j_roles, *j_role, *j_acls;
|
||||
struct dynsec__role *role;
|
||||
|
||||
j_roles = cJSON_GetObjectItem(tree, "roles");
|
||||
@ -269,27 +275,31 @@ int dynsec_roles__config_load(cJSON *tree)
|
||||
|
||||
cJSON_ArrayForEach(j_role, j_roles){
|
||||
if(cJSON_IsObject(j_role) == true){
|
||||
/* Role name */
|
||||
char *rolename;
|
||||
if(json_get_string(j_role, "rolename", &rolename, false) != MOSQ_ERR_SUCCESS){
|
||||
continue;
|
||||
}
|
||||
role = dynsec_roles__find(rolename);
|
||||
if(role){
|
||||
continue;
|
||||
}
|
||||
|
||||
role = mosquitto_calloc(1, sizeof(struct dynsec__role));
|
||||
if(role == NULL){
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
|
||||
/* Role name */
|
||||
jtmp = cJSON_GetObjectItem(j_role, "rolename");
|
||||
if(jtmp == NULL){
|
||||
mosquitto_free(role);
|
||||
continue;
|
||||
}
|
||||
role->rolename = mosquitto_strdup(jtmp->valuestring);
|
||||
role->rolename = mosquitto_strdup(rolename);
|
||||
if(role->rolename == NULL){
|
||||
mosquitto_free(role);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Text name */
|
||||
jtmp = cJSON_GetObjectItem(j_role, "textname");
|
||||
if(jtmp != NULL){
|
||||
role->text_name = mosquitto_strdup(jtmp->valuestring);
|
||||
char *textname;
|
||||
if(json_get_string(j_role, "textname", &textname, false) == MOSQ_ERR_SUCCESS){
|
||||
role->text_name = mosquitto_strdup(textname);
|
||||
if(role->text_name == NULL){
|
||||
mosquitto_free(role->rolename);
|
||||
mosquitto_free(role);
|
||||
@ -298,9 +308,9 @@ int dynsec_roles__config_load(cJSON *tree)
|
||||
}
|
||||
|
||||
/* Text description */
|
||||
jtmp = cJSON_GetObjectItem(j_role, "textdescription");
|
||||
if(jtmp != NULL){
|
||||
role->text_description = mosquitto_strdup(jtmp->valuestring);
|
||||
char *textdescription;
|
||||
if(json_get_string(j_role, "textdescription", &textdescription, false) == MOSQ_ERR_SUCCESS){
|
||||
role->text_description = mosquitto_strdup(textdescription);
|
||||
if(role->text_description == NULL){
|
||||
mosquitto_free(role->text_name);
|
||||
mosquitto_free(role->rolename);
|
||||
@ -594,9 +604,9 @@ int dynsec_roles__process_add_acl(cJSON *j_responses, struct mosquitto *context,
|
||||
char *rolename;
|
||||
char *topic;
|
||||
struct dynsec__role *role;
|
||||
cJSON *jtmp, *j_acltype;
|
||||
struct dynsec__acl **acllist, *acl;
|
||||
int rc;
|
||||
char *acltype;
|
||||
const char *admin_clientid, *admin_username;
|
||||
|
||||
if(json_get_string(command, "rolename", &rolename, false) != MOSQ_ERR_SUCCESS){
|
||||
@ -614,44 +624,37 @@ int dynsec_roles__process_add_acl(cJSON *j_responses, struct mosquitto *context,
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
j_acltype = cJSON_GetObjectItem(command, "acltype");
|
||||
if(j_acltype == NULL || !cJSON_IsString(j_acltype)){
|
||||
if(json_get_string(command, "acltype", &acltype, false) != MOSQ_ERR_SUCCESS){
|
||||
dynsec__command_reply(j_responses, context, "addRoleACL", "Invalid/missing acltype", correlation_data);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
if(!strcasecmp(j_acltype->valuestring, ACL_TYPE_PUB_C_SEND)){
|
||||
if(!strcasecmp(acltype, ACL_TYPE_PUB_C_SEND)){
|
||||
acllist = &role->acls.publish_c_send;
|
||||
}else if(!strcasecmp(j_acltype->valuestring, ACL_TYPE_PUB_C_RECV)){
|
||||
}else if(!strcasecmp(acltype, ACL_TYPE_PUB_C_RECV)){
|
||||
acllist = &role->acls.publish_c_recv;
|
||||
}else if(!strcasecmp(j_acltype->valuestring, ACL_TYPE_SUB_LITERAL)){
|
||||
}else if(!strcasecmp(acltype, ACL_TYPE_SUB_LITERAL)){
|
||||
acllist = &role->acls.subscribe_literal;
|
||||
}else if(!strcasecmp(j_acltype->valuestring, ACL_TYPE_SUB_PATTERN)){
|
||||
}else if(!strcasecmp(acltype, ACL_TYPE_SUB_PATTERN)){
|
||||
acllist = &role->acls.subscribe_pattern;
|
||||
}else if(!strcasecmp(j_acltype->valuestring, ACL_TYPE_UNSUB_LITERAL)){
|
||||
}else if(!strcasecmp(acltype, ACL_TYPE_UNSUB_LITERAL)){
|
||||
acllist = &role->acls.unsubscribe_literal;
|
||||
}else if(!strcasecmp(j_acltype->valuestring, ACL_TYPE_UNSUB_PATTERN)){
|
||||
}else if(!strcasecmp(acltype, ACL_TYPE_UNSUB_PATTERN)){
|
||||
acllist = &role->acls.unsubscribe_pattern;
|
||||
}else{
|
||||
dynsec__command_reply(j_responses, context, "addRoleACL", "Unknown acltype", correlation_data);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
jtmp = cJSON_GetObjectItem(command, "topic");
|
||||
if(jtmp && cJSON_IsString(jtmp)){
|
||||
if(mosquitto_validate_utf8(jtmp->valuestring, (int)strlen(jtmp->valuestring)) != MOSQ_ERR_SUCCESS){
|
||||
if(json_get_string(command, "topic", &topic, false) == MOSQ_ERR_SUCCESS){
|
||||
if(mosquitto_validate_utf8(topic, (int)strlen(topic)) != MOSQ_ERR_SUCCESS){
|
||||
dynsec__command_reply(j_responses, context, "addRoleACL", "Topic not valid UTF-8", correlation_data);
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
rc = mosquitto_sub_topic_check(jtmp->valuestring);
|
||||
rc = mosquitto_sub_topic_check(topic);
|
||||
if(rc != MOSQ_ERR_SUCCESS){
|
||||
dynsec__command_reply(j_responses, context, "addRoleACL", "Invalid ACL topic", correlation_data);
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
topic = mosquitto_strdup(jtmp->valuestring);
|
||||
if(topic == NULL){
|
||||
dynsec__command_reply(j_responses, context, "addRoleACL", "Internal error", correlation_data);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
}else{
|
||||
dynsec__command_reply(j_responses, context, "addRoleACL", "Invalid/missing topic", correlation_data);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
@ -659,18 +662,21 @@ int dynsec_roles__process_add_acl(cJSON *j_responses, struct mosquitto *context,
|
||||
|
||||
HASH_FIND(hh, *acllist, topic, strlen(topic), acl);
|
||||
if(acl){
|
||||
mosquitto_free(topic);
|
||||
dynsec__command_reply(j_responses, context, "addRoleACL", "ACL with this topic already exists", correlation_data);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
acl = mosquitto_calloc(1, sizeof(struct dynsec__acl));
|
||||
if(acl == NULL){
|
||||
mosquitto_free(topic);
|
||||
dynsec__command_reply(j_responses, context, "addRoleACL", "Internal error", correlation_data);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
acl->topic = topic;
|
||||
acl->topic = mosquitto_strdup(topic);
|
||||
if(acl->topic == NULL){
|
||||
mosquitto_free(acl);
|
||||
dynsec__command_reply(j_responses, context, "addRoleACL", "Internal error", correlation_data);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
json_get_int(command, "priority", &acl->priority, true, 0);
|
||||
json_get_bool(command, "allow", &acl->allow, true, false);
|
||||
@ -684,7 +690,7 @@ int dynsec_roles__process_add_acl(cJSON *j_responses, struct mosquitto *context,
|
||||
admin_clientid = mosquitto_client_id(context);
|
||||
admin_username = mosquitto_client_username(context);
|
||||
mosquitto_log_printf(MOSQ_LOG_INFO, "dynsec: %s/%s | addRoleACL | rolename=%s | acltype=%s | topic=%s | priority=%d | allow=%s",
|
||||
admin_clientid, admin_username, rolename, j_acltype->valuestring, topic, acl->priority, acl->allow?"true":"false");
|
||||
admin_clientid, admin_username, rolename, acltype, topic, acl->priority, acl->allow?"true":"false");
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
@ -696,7 +702,7 @@ int dynsec_roles__process_remove_acl(cJSON *j_responses, struct mosquitto *conte
|
||||
struct dynsec__role *role;
|
||||
struct dynsec__acl **acllist, *acl;
|
||||
char *topic;
|
||||
cJSON *j_acltype;
|
||||
char *acltype;
|
||||
int rc;
|
||||
const char *admin_clientid, *admin_username;
|
||||
|
||||
@ -715,22 +721,21 @@ int dynsec_roles__process_remove_acl(cJSON *j_responses, struct mosquitto *conte
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
j_acltype = cJSON_GetObjectItem(command, "acltype");
|
||||
if(j_acltype == NULL || !cJSON_IsString(j_acltype)){
|
||||
if(json_get_string(command, "acltype", &acltype, false) != MOSQ_ERR_SUCCESS){
|
||||
dynsec__command_reply(j_responses, context, "removeRoleACL", "Invalid/missing acltype", correlation_data);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
if(!strcasecmp(j_acltype->valuestring, ACL_TYPE_PUB_C_SEND)){
|
||||
if(!strcasecmp(acltype, ACL_TYPE_PUB_C_SEND)){
|
||||
acllist = &role->acls.publish_c_send;
|
||||
}else if(!strcasecmp(j_acltype->valuestring, ACL_TYPE_PUB_C_RECV)){
|
||||
}else if(!strcasecmp(acltype, ACL_TYPE_PUB_C_RECV)){
|
||||
acllist = &role->acls.publish_c_recv;
|
||||
}else if(!strcasecmp(j_acltype->valuestring, ACL_TYPE_SUB_LITERAL)){
|
||||
}else if(!strcasecmp(acltype, ACL_TYPE_SUB_LITERAL)){
|
||||
acllist = &role->acls.subscribe_literal;
|
||||
}else if(!strcasecmp(j_acltype->valuestring, ACL_TYPE_SUB_PATTERN)){
|
||||
}else if(!strcasecmp(acltype, ACL_TYPE_SUB_PATTERN)){
|
||||
acllist = &role->acls.subscribe_pattern;
|
||||
}else if(!strcasecmp(j_acltype->valuestring, ACL_TYPE_UNSUB_LITERAL)){
|
||||
}else if(!strcasecmp(acltype, ACL_TYPE_UNSUB_LITERAL)){
|
||||
acllist = &role->acls.unsubscribe_literal;
|
||||
}else if(!strcasecmp(j_acltype->valuestring, ACL_TYPE_UNSUB_PATTERN)){
|
||||
}else if(!strcasecmp(acltype, ACL_TYPE_UNSUB_PATTERN)){
|
||||
acllist = &role->acls.unsubscribe_pattern;
|
||||
}else{
|
||||
dynsec__command_reply(j_responses, context, "removeRoleACL", "Unknown acltype", correlation_data);
|
||||
@ -762,7 +767,7 @@ int dynsec_roles__process_remove_acl(cJSON *j_responses, struct mosquitto *conte
|
||||
admin_clientid = mosquitto_client_id(context);
|
||||
admin_username = mosquitto_client_username(context);
|
||||
mosquitto_log_printf(MOSQ_LOG_INFO, "dynsec: %s/%s | removeRoleACL | rolename=%s | acltype=%s | topic=%s",
|
||||
admin_clientid, admin_username, rolename, j_acltype->valuestring, topic);
|
||||
admin_clientid, admin_username, rolename, acltype, topic);
|
||||
|
||||
}else{
|
||||
dynsec__command_reply(j_responses, context, "removeRoleACL", "ACL not found", correlation_data);
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
MAJOR=2
|
||||
MINOR=0
|
||||
REVISION=15
|
||||
REVISION=16
|
||||
|
||||
sed -i "s/^VERSION=.*/VERSION=${MAJOR}.${MINOR}.${REVISION}/" config.mk
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
name: mosquitto
|
||||
version: 2.0.15
|
||||
version: 2.0.16
|
||||
summary: Eclipse Mosquitto MQTT broker
|
||||
description: This is a message broker that supports version 5.0, 3.1.1, and 3.1 of the MQTT
|
||||
protocol.
|
||||
|
@ -126,6 +126,9 @@ int bridge__new(struct mosquitto__bridge *bridge)
|
||||
}
|
||||
new_context->retain_available = bridge->outgoing_retain;
|
||||
new_context->protocol = bridge->protocol_version;
|
||||
if(!bridge->clean_start_local){
|
||||
new_context->session_expiry_interval = UINT32_MAX;
|
||||
}
|
||||
|
||||
bridges = mosquitto__realloc(db.bridges, (size_t)(db.bridge_count+1)*sizeof(struct mosquitto *));
|
||||
if(bridges){
|
||||
|
12
src/conf.c
12
src/conf.c
@ -187,7 +187,7 @@ static void config__init_reload(struct mosquitto__config *config)
|
||||
config->log_timestamp = true;
|
||||
mosquitto__free(config->log_timestamp_format);
|
||||
config->log_timestamp_format = NULL;
|
||||
config->max_keepalive = 65535;
|
||||
config->max_keepalive = 0;
|
||||
config->max_packet_size = 0;
|
||||
config->max_inflight_messages = 20;
|
||||
config->max_queued_messages = 1000;
|
||||
@ -1533,15 +1533,16 @@ static int config__read_file_core(struct mosquitto__config *config, bool reload,
|
||||
}else if(!strcmp(token, "dlt")){
|
||||
cr->log_dest |= MQTT3_LOG_DLT;
|
||||
}else if(!strcmp(token, "file")){
|
||||
cr->log_dest |= MQTT3_LOG_FILE;
|
||||
if(config->log_fptr || config->log_file){
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error: Duplicate \"log_dest file\" value.");
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
/* Get remaining string. */
|
||||
token = &token[strlen(token)+1];
|
||||
while(token[0] == ' ' || token[0] == '\t'){
|
||||
token++;
|
||||
token = saveptr;
|
||||
if(token && token[0]){
|
||||
while(token[0] == ' ' || token[0] == '\t'){
|
||||
token++;
|
||||
}
|
||||
}
|
||||
if(token[0]){
|
||||
config->log_file = mosquitto__strdup(token);
|
||||
@ -1553,6 +1554,7 @@ static int config__read_file_core(struct mosquitto__config *config, bool reload,
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error: Empty \"log_dest file\" value in configuration.");
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
cr->log_dest |= MQTT3_LOG_FILE;
|
||||
}else{
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid log_dest value (%s).", token);
|
||||
return MOSQ_ERR_INVAL;
|
||||
|
@ -83,9 +83,9 @@ struct mosquitto *context__init(mosq_sock_t sock)
|
||||
}
|
||||
}
|
||||
context->bridge = NULL;
|
||||
context->msgs_in.inflight_maximum = db.config->max_inflight_messages;
|
||||
context->msgs_in.inflight_maximum = 1;
|
||||
context->msgs_out.inflight_maximum = db.config->max_inflight_messages;
|
||||
context->msgs_in.inflight_quota = db.config->max_inflight_messages;
|
||||
context->msgs_in.inflight_quota = 1;
|
||||
context->msgs_out.inflight_quota = db.config->max_inflight_messages;
|
||||
context->max_qos = 2;
|
||||
#ifdef WITH_TLS
|
||||
@ -98,6 +98,27 @@ struct mosquitto *context__init(mosq_sock_t sock)
|
||||
return context;
|
||||
}
|
||||
|
||||
static void context__cleanup_out_packets(struct mosquitto *context)
|
||||
{
|
||||
struct mosquitto__packet *packet;
|
||||
|
||||
if(!context) return;
|
||||
|
||||
if(context->current_out_packet){
|
||||
packet__cleanup(context->current_out_packet);
|
||||
mosquitto__free(context->current_out_packet);
|
||||
context->current_out_packet = NULL;
|
||||
}
|
||||
while(context->out_packet){
|
||||
packet__cleanup(context->out_packet);
|
||||
packet = context->out_packet;
|
||||
context->out_packet = context->out_packet->next;
|
||||
mosquitto__free(packet);
|
||||
}
|
||||
context->out_packet_count = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This will result in any outgoing packets going unsent. If we're disconnected
|
||||
* forcefully then it is usually an error condition and shouldn't be a problem,
|
||||
@ -106,8 +127,6 @@ struct mosquitto *context__init(mosq_sock_t sock)
|
||||
*/
|
||||
void context__cleanup(struct mosquitto *context, bool force_free)
|
||||
{
|
||||
struct mosquitto__packet *packet;
|
||||
|
||||
if(!context) return;
|
||||
|
||||
if(force_free){
|
||||
@ -121,6 +140,7 @@ void context__cleanup(struct mosquitto *context, bool force_free)
|
||||
#endif
|
||||
|
||||
alias__free_all(context);
|
||||
context__cleanup_out_packets(context);
|
||||
|
||||
mosquitto__free(context->auth_method);
|
||||
context->auth_method = NULL;
|
||||
@ -148,18 +168,7 @@ void context__cleanup(struct mosquitto *context, bool force_free)
|
||||
context->id = NULL;
|
||||
}
|
||||
packet__cleanup(&(context->in_packet));
|
||||
if(context->current_out_packet){
|
||||
packet__cleanup(context->current_out_packet);
|
||||
mosquitto__free(context->current_out_packet);
|
||||
context->current_out_packet = NULL;
|
||||
}
|
||||
while(context->out_packet){
|
||||
packet__cleanup(context->out_packet);
|
||||
packet = context->out_packet;
|
||||
context->out_packet = context->out_packet->next;
|
||||
mosquitto__free(packet);
|
||||
}
|
||||
context->out_packet_count = 0;
|
||||
context__cleanup_out_packets(context);
|
||||
#if defined(WITH_BROKER) && defined(__GLIBC__) && defined(WITH_ADNS)
|
||||
if(context->adns){
|
||||
gai_cancel(context->adns);
|
||||
@ -214,19 +223,20 @@ void context__disconnect(struct mosquitto *context)
|
||||
|
||||
context__send_will(context);
|
||||
net__socket_close(context);
|
||||
if(context->session_expiry_interval == 0){
|
||||
/* Client session is due to be expired now */
|
||||
#ifdef WITH_BRIDGE
|
||||
if(context->bridge == NULL)
|
||||
if(context->bridge == NULL)
|
||||
/* Outgoing bridge connection never expire */
|
||||
#endif
|
||||
{
|
||||
{
|
||||
if(context->session_expiry_interval == 0){
|
||||
/* Client session is due to be expired now */
|
||||
if(context->will_delay_interval == 0){
|
||||
/* This will be done later, after the will is published for delay>0. */
|
||||
context__add_to_disused(context);
|
||||
}
|
||||
}else{
|
||||
session_expiry__add(context);
|
||||
}
|
||||
}else{
|
||||
session_expiry__add(context);
|
||||
}
|
||||
keepalive__remove(context);
|
||||
mosquitto__set_state(context, mosq_cs_disconnected);
|
||||
|
@ -555,7 +555,7 @@ int db__message_insert(struct mosquitto *context, uint16_t mid, enum mosquitto_m
|
||||
}
|
||||
#endif
|
||||
|
||||
msg = mosquitto__malloc(sizeof(struct mosquitto_client_msg));
|
||||
msg = mosquitto__calloc(1, sizeof(struct mosquitto_client_msg));
|
||||
if(!msg) return MOSQ_ERR_NOMEM;
|
||||
msg->prev = NULL;
|
||||
msg->next = NULL;
|
||||
@ -613,6 +613,8 @@ int db__message_insert(struct mosquitto *context, uint16_t mid, enum mosquitto_m
|
||||
|
||||
if(dir == mosq_md_out && msg->qos > 0 && state != mosq_ms_queued){
|
||||
util__decrement_send_quota(context);
|
||||
}else if(dir == mosq_md_in && msg->qos > 0 && state != mosq_ms_queued){
|
||||
util__decrement_receive_quota(context);
|
||||
}
|
||||
|
||||
if(dir == mosq_md_out && update){
|
||||
@ -796,23 +798,24 @@ int db__message_store(const struct mosquitto *source, struct mosquitto_msg_store
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int db__message_store_find(struct mosquitto *context, uint16_t mid, struct mosquitto_msg_store **stored)
|
||||
int db__message_store_find(struct mosquitto *context, uint16_t mid, struct mosquitto_client_msg **client_msg)
|
||||
{
|
||||
struct mosquitto_client_msg *tail;
|
||||
struct mosquitto_client_msg *cmsg;
|
||||
|
||||
*client_msg = NULL;
|
||||
|
||||
if(!context) return MOSQ_ERR_INVAL;
|
||||
|
||||
*stored = NULL;
|
||||
DL_FOREACH(context->msgs_in.inflight, tail){
|
||||
if(tail->store->source_mid == mid){
|
||||
*stored = tail->store;
|
||||
DL_FOREACH(context->msgs_in.inflight, cmsg){
|
||||
if(cmsg->store->source_mid == mid){
|
||||
*client_msg = cmsg;
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
DL_FOREACH(context->msgs_in.queued, tail){
|
||||
if(tail->store->source_mid == mid){
|
||||
*stored = tail->store;
|
||||
DL_FOREACH(context->msgs_in.queued, cmsg){
|
||||
if(cmsg->store->source_mid == mid){
|
||||
*client_msg = cmsg;
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
}
|
||||
@ -914,6 +917,7 @@ static int db__message_reconnect_reset_incoming(struct mosquitto *context)
|
||||
}else{
|
||||
/* Message state can be preserved here because it should match
|
||||
* whatever the client has got. */
|
||||
msg->dup = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -924,6 +928,7 @@ static int db__message_reconnect_reset_incoming(struct mosquitto *context)
|
||||
* will be sent out of order.
|
||||
*/
|
||||
DL_FOREACH_SAFE(context->msgs_in.queued, msg, tmp){
|
||||
msg->dup = 0;
|
||||
db__msg_add_to_queued_stats(&context->msgs_in, msg);
|
||||
if(db__ready_for_flight(context, mosq_md_in, msg->qos)){
|
||||
switch(msg->qos){
|
||||
|
@ -375,6 +375,10 @@ static int will__read(struct mosquitto *context, const char *client_id, struct m
|
||||
will_struct->msg.topic = will_topic_mount;
|
||||
}
|
||||
|
||||
if(!strncmp(will_struct->msg.topic, "$CONTROL/", strlen("$CONTROL/"))){
|
||||
rc = MOSQ_ERR_ACL_DENIED;
|
||||
goto error_cleanup;
|
||||
}
|
||||
rc = mosquitto_pub_topic_check(will_struct->msg.topic);
|
||||
if(rc) goto error_cleanup;
|
||||
|
||||
@ -790,11 +794,22 @@ int handle__connect(struct mosquitto *context)
|
||||
rc = MOSQ_ERR_AUTH;
|
||||
goto handle_connect_error;
|
||||
}
|
||||
const char *new_username;
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
context->username = mosquitto__strdup((char *) ASN1_STRING_data(name_asn1));
|
||||
new_username = (const char *) ASN1_STRING_data(name_asn1);
|
||||
#else
|
||||
context->username = mosquitto__strdup((char *) ASN1_STRING_get0_data(name_asn1));
|
||||
new_username = (const char *) ASN1_STRING_get0_data(name_asn1);
|
||||
#endif
|
||||
if(mosquitto_validate_utf8(new_username, (int)strlen(new_username))){
|
||||
if(context->protocol == mosq_p_mqtt5){
|
||||
send__connack(context, 0, MQTT_RC_BAD_USERNAME_OR_PASSWORD, NULL);
|
||||
}else{
|
||||
send__connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD, NULL);
|
||||
}
|
||||
X509_free(client_cert);
|
||||
return MOSQ_ERR_AUTH;
|
||||
}
|
||||
context->username = mosquitto__strdup(new_username);
|
||||
if(!context->username){
|
||||
if(context->protocol == mosq_p_mqtt5){
|
||||
send__connack(context, 0, MQTT_RC_SERVER_UNAVAILABLE, NULL);
|
||||
@ -936,6 +951,7 @@ int handle__connect(struct mosquitto *context)
|
||||
|
||||
|
||||
handle_connect_error:
|
||||
mosquitto_property_free_all(&properties);
|
||||
mosquitto__free(auth_data);
|
||||
mosquitto__free(client_id);
|
||||
mosquitto__free(username);
|
||||
@ -946,7 +962,13 @@ handle_connect_error:
|
||||
mosquitto__free(will_struct->msg.topic);
|
||||
mosquitto__free(will_struct);
|
||||
}
|
||||
context->will = NULL;
|
||||
if(context->will){
|
||||
mosquitto_property_free_all(&context->will->properties);
|
||||
mosquitto__free(context->will->msg.payload);
|
||||
mosquitto__free(context->will->msg.topic);
|
||||
mosquitto__free(context->will);
|
||||
context->will = NULL;
|
||||
}
|
||||
#ifdef WITH_TLS
|
||||
if(client_cert) X509_free(client_cert);
|
||||
#endif
|
||||
|
@ -42,6 +42,7 @@ int handle__publish(struct mosquitto *context)
|
||||
uint8_t header = context->in_packet.command;
|
||||
int res = 0;
|
||||
struct mosquitto_msg_store *msg, *stored = NULL;
|
||||
struct mosquitto_client_msg *cmsg_stored = NULL;
|
||||
size_t len;
|
||||
uint16_t slen;
|
||||
char *topic_mount;
|
||||
@ -287,24 +288,24 @@ int handle__publish(struct mosquitto *context)
|
||||
}
|
||||
|
||||
if(msg->qos > 0){
|
||||
db__message_store_find(context, msg->source_mid, &stored);
|
||||
db__message_store_find(context, msg->source_mid, &cmsg_stored);
|
||||
}
|
||||
|
||||
if(stored && msg->source_mid != 0 &&
|
||||
(stored->qos != msg->qos
|
||||
|| stored->payloadlen != msg->payloadlen
|
||||
|| strcmp(stored->topic, msg->topic)
|
||||
|| memcmp(stored->payload, msg->payload, msg->payloadlen) )){
|
||||
if(cmsg_stored && cmsg_stored->store && msg->source_mid != 0 &&
|
||||
(cmsg_stored->store->qos != msg->qos
|
||||
|| cmsg_stored->store->payloadlen != msg->payloadlen
|
||||
|| strcmp(cmsg_stored->store->topic, msg->topic)
|
||||
|| memcmp(cmsg_stored->store->payload, msg->payload, msg->payloadlen) )){
|
||||
|
||||
log__printf(NULL, MOSQ_LOG_WARNING, "Reused message ID %u from %s detected. Clearing from storage.", msg->source_mid, context->id);
|
||||
db__message_remove_incoming(context, msg->source_mid);
|
||||
stored = NULL;
|
||||
cmsg_stored = NULL;
|
||||
}
|
||||
|
||||
if(!stored){
|
||||
if(!cmsg_stored){
|
||||
if(msg->qos == 0
|
||||
|| db__ready_for_flight(context, mosq_md_in, msg->qos)
|
||||
|| db__ready_for_queue(context, msg->qos, &context->msgs_in)){
|
||||
){
|
||||
|
||||
dup = 0;
|
||||
rc = db__message_store(context, msg, message_expiry_interval, 0, mosq_mo_client);
|
||||
@ -316,10 +317,13 @@ int handle__publish(struct mosquitto *context)
|
||||
}
|
||||
stored = msg;
|
||||
msg = NULL;
|
||||
dup = 0;
|
||||
}else{
|
||||
db__msg_store_free(msg);
|
||||
msg = NULL;
|
||||
dup = 1;
|
||||
stored = cmsg_stored->store;
|
||||
cmsg_stored->dup++;
|
||||
dup = cmsg_stored->dup;
|
||||
}
|
||||
|
||||
switch(stored->qos){
|
||||
@ -345,11 +349,17 @@ int handle__publish(struct mosquitto *context)
|
||||
}else{
|
||||
res = 0;
|
||||
}
|
||||
|
||||
/* db__message_insert() returns 2 to indicate dropped message
|
||||
* due to queue. This isn't an error so don't disconnect them. */
|
||||
/* FIXME - this is no longer necessary due to failing early above */
|
||||
if(!res){
|
||||
if(send__pubrec(context, stored->source_mid, 0, NULL)) rc = 1;
|
||||
if(dup == 0 || dup == 1){
|
||||
rc2 = send__pubrec(context, stored->source_mid, 0, NULL);
|
||||
if(rc2) rc = rc2;
|
||||
}else{
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
}else if(res == 1){
|
||||
rc = 1;
|
||||
}
|
||||
@ -374,6 +384,9 @@ process_bad_message:
|
||||
}
|
||||
db__msg_store_free(msg);
|
||||
}
|
||||
if(context->out_packet_count >= db.config->max_queued_messages){
|
||||
rc = MQTT_RC_QUOTA_EXCEEDED;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ Contributors:
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#ifndef WIN32
|
||||
#include <syslog.h>
|
||||
#endif
|
||||
@ -129,11 +130,16 @@ int log__init(struct mosquitto__config *config)
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open log file %s for writing.", config->log_file);
|
||||
}
|
||||
}
|
||||
if(log_destinations & MQTT3_LOG_STDOUT){
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
}
|
||||
#ifdef WITH_DLT
|
||||
dlt_fifo_check();
|
||||
if(dlt_allowed){
|
||||
DLT_REGISTER_APP("MQTT","mosquitto log");
|
||||
dlt_register_context(&dltContext, "MQTT", "mosquitto DLT context");
|
||||
if(log_destinations & MQTT3_LOG_DLT){
|
||||
dlt_fifo_check();
|
||||
if(dlt_allowed){
|
||||
DLT_REGISTER_APP("MQTT","mosquitto log");
|
||||
dlt_register_context(&dltContext, "MQTT", "mosquitto DLT context");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
@ -291,7 +297,7 @@ static int log__vprintf(unsigned int priority, const char *fmt, va_list va)
|
||||
log_line_pos = (size_t)snprintf(log_line, sizeof(log_line), "Time error");
|
||||
}
|
||||
}else{
|
||||
log_line_pos = (size_t)snprintf(log_line, sizeof(log_line), "%d", (int)db.now_real_s);
|
||||
log_line_pos = (size_t)snprintf(log_line, sizeof(log_line), "%" PRIu64, (uint64_t)db.now_real_s);
|
||||
}
|
||||
if(log_line_pos < sizeof(log_line)-3){
|
||||
log_line[log_line_pos] = ':';
|
||||
|
@ -160,9 +160,18 @@ static void mosquitto__daemonise(void)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
assert(freopen("/dev/null", "r", stdin));
|
||||
assert(freopen("/dev/null", "w", stdout));
|
||||
assert(freopen("/dev/null", "w", stderr));
|
||||
if(!freopen("/dev/null", "r", stdin)){
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error whilst daemonising (%s): %s", "stdin", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if(!freopen("/dev/null", "w", stdout)){
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error whilst daemonising (%s): %s", "stdout", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if(!freopen("/dev/null", "w", stderr)){
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error whilst daemonising (%s): %s", "stderr", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
#else
|
||||
log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Can't start in daemon mode in Windows.");
|
||||
#endif
|
||||
@ -475,7 +484,12 @@ int main(int argc, char *argv[])
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
_setmaxstdio(2048);
|
||||
if(_setmaxstdio(8192) != 8192){
|
||||
/* Old limit was 2048 */
|
||||
if(_setmaxstdio(2048) != 2048){
|
||||
log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Unable to increase maximum allowed connections. This session may be limited to 512 connections.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(&db, 0, sizeof(struct mosquitto_db));
|
||||
|
@ -394,7 +394,7 @@ struct mosquitto_client_msg{
|
||||
bool retain;
|
||||
enum mosquitto_msg_direction direction;
|
||||
enum mosquitto_msg_state state;
|
||||
bool dup;
|
||||
uint8_t dup;
|
||||
};
|
||||
|
||||
|
||||
@ -651,7 +651,7 @@ void db__message_dequeue_first(struct mosquitto *context, struct mosquitto_msg_d
|
||||
int db__messages_delete(struct mosquitto *context, bool force_free);
|
||||
int db__messages_easy_queue(struct mosquitto *context, const char *topic, uint8_t qos, uint32_t payloadlen, const void *payload, int retain, uint32_t message_expiry_interval, mosquitto_property **properties);
|
||||
int db__message_store(const struct mosquitto *source, struct mosquitto_msg_store *stored, uint32_t message_expiry_interval, dbid_t store_id, enum mosquitto_msg_origin origin);
|
||||
int db__message_store_find(struct mosquitto *context, uint16_t mid, struct mosquitto_msg_store **stored);
|
||||
int db__message_store_find(struct mosquitto *context, uint16_t mid, struct mosquitto_client_msg **client_msg);
|
||||
void db__msg_store_add(struct mosquitto_msg_store *store);
|
||||
void db__msg_store_remove(struct mosquitto_msg_store *store);
|
||||
void db__msg_store_ref_inc(struct mosquitto_msg_store *store);
|
||||
|
98
src/net.c
98
src/net.c
@ -56,6 +56,7 @@ Contributors:
|
||||
#include "mosquitto_broker_internal.h"
|
||||
#include "mqtt_protocol.h"
|
||||
#include "memory_mosq.h"
|
||||
#include "misc_mosq.h"
|
||||
#include "net_mosq.h"
|
||||
#include "util_mosq.h"
|
||||
|
||||
@ -295,6 +296,10 @@ static unsigned int psk_server_callback(SSL *ssl, const char *identity, unsigned
|
||||
}
|
||||
|
||||
if(listener->use_identity_as_username){
|
||||
if(mosquitto_validate_utf8(identity, (int)strlen(identity))){
|
||||
mosquitto__free(psk_key);
|
||||
return 0;
|
||||
}
|
||||
context->username = mosquitto__strdup(identity);
|
||||
if(!context->username){
|
||||
mosquitto__free(psk_key);
|
||||
@ -343,7 +348,7 @@ int net__tls_server_ctx(struct mosquitto__listener *listener)
|
||||
#endif
|
||||
|
||||
if(listener->tls_version == NULL){
|
||||
SSL_CTX_set_options(listener->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1);
|
||||
SSL_CTX_set_options(listener->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
|
||||
#ifdef SSL_OP_NO_TLSv1_3
|
||||
}else if(!strcmp(listener->tls_version, "tlsv1.3")){
|
||||
SSL_CTX_set_options(listener->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2);
|
||||
@ -416,7 +421,7 @@ int net__tls_server_ctx(struct mosquitto__listener *listener)
|
||||
#endif
|
||||
|
||||
if(listener->dhparamfile){
|
||||
dhparamfile = fopen(listener->dhparamfile, "r");
|
||||
dhparamfile = mosquitto__fopen(listener->dhparamfile, "r", true);
|
||||
if(!dhparamfile){
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error loading dhparamfile \"%s\".", listener->dhparamfile);
|
||||
return MOSQ_ERR_TLS;
|
||||
@ -479,7 +484,7 @@ int net__load_certificates(struct mosquitto__listener *listener)
|
||||
net__print_ssl_error(NULL);
|
||||
return MOSQ_ERR_TLS;
|
||||
}
|
||||
if(listener->tls_engine == NULL){
|
||||
if(listener->tls_engine == NULL || listener->tls_keyform == mosq_k_pem){
|
||||
rc = SSL_CTX_use_PrivateKey_file(listener->ssl_ctx, listener->keyfile, SSL_FILETYPE_PEM);
|
||||
if(rc != 1){
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load server key file \"%s\". Check keyfile.", listener->keyfile);
|
||||
@ -622,6 +627,8 @@ static int net__bind_interface(struct mosquitto__listener *listener, struct addr
|
||||
* matching interface in the later bind().
|
||||
*/
|
||||
struct ifaddrs *ifaddr, *ifa;
|
||||
bool have_interface = false;
|
||||
|
||||
if(getifaddrs(&ifaddr) < 0){
|
||||
net__print_error(MOSQ_LOG_ERR, "Error: %s");
|
||||
return MOSQ_ERR_ERRNO;
|
||||
@ -632,49 +639,56 @@ static int net__bind_interface(struct mosquitto__listener *listener, struct addr
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!strcasecmp(listener->bind_interface, ifa->ifa_name)
|
||||
&& ifa->ifa_addr->sa_family == rp->ai_addr->sa_family){
|
||||
if(!strcasecmp(listener->bind_interface, ifa->ifa_name)){
|
||||
have_interface = true;
|
||||
|
||||
if(rp->ai_addr->sa_family == AF_INET){
|
||||
if(listener->host &&
|
||||
memcmp(&((struct sockaddr_in *)rp->ai_addr)->sin_addr,
|
||||
&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
|
||||
sizeof(struct in_addr))){
|
||||
if(ifa->ifa_addr->sa_family == rp->ai_addr->sa_family){
|
||||
if(rp->ai_addr->sa_family == AF_INET){
|
||||
if(listener->host &&
|
||||
memcmp(&((struct sockaddr_in *)rp->ai_addr)->sin_addr,
|
||||
&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
|
||||
sizeof(struct in_addr))){
|
||||
|
||||
log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Interface address for %s does not match specified listener address (%s).",
|
||||
listener->bind_interface, listener->host);
|
||||
return MOSQ_ERR_INVAL;
|
||||
}else{
|
||||
memcpy(&((struct sockaddr_in *)rp->ai_addr)->sin_addr,
|
||||
&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
|
||||
sizeof(struct in_addr));
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error: Interface address for %s does not match specified listener address (%s).",
|
||||
listener->bind_interface, listener->host);
|
||||
return MOSQ_ERR_INVAL;
|
||||
}else{
|
||||
memcpy(&((struct sockaddr_in *)rp->ai_addr)->sin_addr,
|
||||
&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
|
||||
sizeof(struct in_addr));
|
||||
|
||||
freeifaddrs(ifaddr);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
}else if(rp->ai_addr->sa_family == AF_INET6){
|
||||
if(listener->host &&
|
||||
memcmp(&((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr,
|
||||
&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr,
|
||||
sizeof(struct in6_addr))){
|
||||
freeifaddrs(ifaddr);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
}else if(rp->ai_addr->sa_family == AF_INET6){
|
||||
if(listener->host &&
|
||||
memcmp(&((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr,
|
||||
&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr,
|
||||
sizeof(struct in6_addr))){
|
||||
|
||||
log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Interface address for %s does not match specified listener address (%s).",
|
||||
listener->bind_interface, listener->host);
|
||||
return MOSQ_ERR_INVAL;
|
||||
}else{
|
||||
memcpy(&((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr,
|
||||
&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
freeifaddrs(ifaddr);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error: Interface address for %s does not match specified listener address (%s).",
|
||||
listener->bind_interface, listener->host);
|
||||
return MOSQ_ERR_INVAL;
|
||||
}else{
|
||||
memcpy(&((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr,
|
||||
&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
freeifaddrs(ifaddr);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifaddr);
|
||||
log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Interface %s does not support %s configuration.",
|
||||
listener->bind_interface, rp->ai_addr->sa_family == AF_INET ? "IPv4" : "IPv6");
|
||||
return MOSQ_ERR_NOT_FOUND;
|
||||
if(have_interface){
|
||||
log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Interface %s does not support %s configuration.",
|
||||
listener->bind_interface, rp->ai_addr->sa_family == AF_INET ? "IPv4" : "IPv6");
|
||||
return MOSQ_ERR_NOT_SUPPORTED;
|
||||
}else{
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error: Interface %s does not exist.", listener->bind_interface);
|
||||
return MOSQ_ERR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -756,10 +770,16 @@ static int net__socket_listen_tcp(struct mosquitto__listener *listener)
|
||||
if(listener->bind_interface){
|
||||
/* It might be possible that an interface does not support all relevant sa_families.
|
||||
* We should successfully find at least one. */
|
||||
if(net__bind_interface(listener, rp)){
|
||||
rc = net__bind_interface(listener, rp);
|
||||
if(rc){
|
||||
COMPAT_CLOSE(sock);
|
||||
listener->sock_count--;
|
||||
continue;
|
||||
if(rc == MOSQ_ERR_NOT_FOUND || rc == MOSQ_ERR_INVAL){
|
||||
freeaddrinfo(ainfo);
|
||||
return rc;
|
||||
}else{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
interface_bound = true;
|
||||
}
|
||||
|
@ -201,9 +201,7 @@ int pw__memcmp_const(const void *a, const void *b, size_t len)
|
||||
if(!a || !b) return 1;
|
||||
|
||||
for(i=0; i<len; i++){
|
||||
if( ((char *)a)[i] != ((char *)b)[i] ){
|
||||
rc = 1;
|
||||
}
|
||||
rc |= ((char *)a)[i] ^ ((char *)b)[i];
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -427,7 +427,7 @@ int persist__restore(void)
|
||||
|
||||
db.msg_store_load = NULL;
|
||||
|
||||
fptr = mosquitto__fopen(db.config->persistence_filepath, "rb", false);
|
||||
fptr = mosquitto__fopen(db.config->persistence_filepath, "rb", true);
|
||||
if(fptr == NULL) return MOSQ_ERR_SUCCESS;
|
||||
rlen = fread(&header, 1, 15, fptr);
|
||||
if(rlen == 0){
|
||||
|
@ -180,9 +180,9 @@ int persist__chunk_msg_store_read_v234(FILE *db_fptr, struct P_msg_store *chunk,
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
read_e(db_fptr, chunk->payload, chunk->F.payloadlen);
|
||||
/* Ensure zero terminated regardless of contents */
|
||||
((uint8_t *)chunk->payload)[chunk->F.payloadlen] = 0;
|
||||
read_e(db_fptr, chunk->payload, chunk->F.payloadlen);
|
||||
}
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
|
@ -203,9 +203,9 @@ int persist__chunk_msg_store_read_v56(FILE *db_fptr, struct P_msg_store *chunk,
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
read_e(db_fptr, chunk->payload, chunk->F.payloadlen);
|
||||
/* Ensure zero terminated regardless of contents */
|
||||
((uint8_t *)chunk->payload)[chunk->F.payloadlen] = 0;
|
||||
read_e(db_fptr, chunk->payload, chunk->F.payloadlen);
|
||||
}
|
||||
|
||||
if(length > 0){
|
||||
|
@ -47,8 +47,6 @@ static int persist__client_messages_save(FILE *db_fptr, struct mosquitto *contex
|
||||
assert(db_fptr);
|
||||
assert(context);
|
||||
|
||||
memset(&chunk, 0, sizeof(struct P_client_msg));
|
||||
|
||||
cmsg = queue;
|
||||
while(cmsg){
|
||||
if(!strncmp(cmsg->store->topic, "$SYS", 4)
|
||||
@ -61,6 +59,8 @@ static int persist__client_messages_save(FILE *db_fptr, struct mosquitto *contex
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(&chunk, 0, sizeof(struct P_client_msg));
|
||||
|
||||
chunk.F.store_id = cmsg->store->db_id;
|
||||
chunk.F.mid = cmsg->mid;
|
||||
chunk.F.id_len = (uint16_t)strlen(context->id);
|
||||
@ -91,8 +91,6 @@ static int persist__message_store_save(FILE *db_fptr)
|
||||
|
||||
assert(db_fptr);
|
||||
|
||||
memset(&chunk, 0, sizeof(struct P_msg_store));
|
||||
|
||||
stored = db.msg_store;
|
||||
while(stored){
|
||||
if(stored->ref_count < 1 || stored->topic == NULL){
|
||||
@ -100,6 +98,8 @@ static int persist__message_store_save(FILE *db_fptr)
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(&chunk, 0, sizeof(struct P_msg_store));
|
||||
|
||||
if(!strncmp(stored->topic, "$SYS", 4)){
|
||||
if(stored->ref_count <= 1 && stored->dest_id_count == 0){
|
||||
/* $SYS messages that are only retained shouldn't be persisted. */
|
||||
@ -164,14 +164,17 @@ static int persist__client_save(FILE *db_fptr)
|
||||
|
||||
assert(db_fptr);
|
||||
|
||||
memset(&chunk, 0, sizeof(struct P_client));
|
||||
|
||||
HASH_ITER(hh_id, db.contexts_by_id, context, ctxt_tmp){
|
||||
if(context && (context->clean_start == false
|
||||
memset(&chunk, 0, sizeof(struct P_client));
|
||||
|
||||
if(context &&
|
||||
#ifdef WITH_BRIDGE
|
||||
|| (context->bridge && context->bridge->clean_start_local == false)
|
||||
((!context->bridge && context->clean_start == false)
|
||||
|| (context->bridge && context->bridge->clean_start_local == false))
|
||||
#else
|
||||
context->clean_start == false
|
||||
#endif
|
||||
)){
|
||||
){
|
||||
chunk.F.session_expiry_time = context->session_expiry_time;
|
||||
if(context->session_expiry_interval != 0 && context->session_expiry_interval != UINT32_MAX && context->session_expiry_time == 0){
|
||||
chunk.F.session_expiry_time = context->session_expiry_interval + db.now_real_s;
|
||||
@ -221,8 +224,6 @@ static int persist__subs_save(FILE *db_fptr, struct mosquitto__subhier *node, co
|
||||
size_t slen;
|
||||
int rc;
|
||||
|
||||
memset(&sub_chunk, 0, sizeof(struct P_sub));
|
||||
|
||||
slen = strlen(topic) + node->topic_len + 2;
|
||||
thistopic = mosquitto__malloc(sizeof(char)*slen);
|
||||
if(!thistopic) return MOSQ_ERR_NOMEM;
|
||||
@ -235,6 +236,8 @@ static int persist__subs_save(FILE *db_fptr, struct mosquitto__subhier *node, co
|
||||
sub = node->subs;
|
||||
while(sub){
|
||||
if(sub->context->clean_start == false && sub->context->id){
|
||||
memset(&sub_chunk, 0, sizeof(struct P_sub));
|
||||
|
||||
sub_chunk.F.identifier = sub->identifier;
|
||||
sub_chunk.F.id_len = (uint16_t)strlen(sub->context->id);
|
||||
sub_chunk.F.topic_len = (uint16_t)strlen(thistopic);
|
||||
@ -278,10 +281,10 @@ static int persist__retain_save(FILE *db_fptr, struct mosquitto__retainhier *nod
|
||||
struct P_retain retain_chunk;
|
||||
int rc;
|
||||
|
||||
memset(&retain_chunk, 0, sizeof(struct P_retain));
|
||||
|
||||
if(node->retained && strncmp(node->retained->topic, "$SYS", 4)){
|
||||
/* Don't save $SYS messages. */
|
||||
memset(&retain_chunk, 0, sizeof(struct P_retain));
|
||||
|
||||
retain_chunk.F.store_id = node->retained->db_id;
|
||||
rc = persist__chunk_retain_write_v6(db_fptr, &retain_chunk);
|
||||
if(rc){
|
||||
|
@ -244,6 +244,9 @@ int mosquitto_set_username(struct mosquitto *client, const char *username)
|
||||
if(!client) return MOSQ_ERR_INVAL;
|
||||
|
||||
if(username){
|
||||
if(mosquitto_validate_utf8(username, (int)strlen(username))){
|
||||
return MOSQ_ERR_MALFORMED_UTF8;
|
||||
}
|
||||
u_dup = mosquitto__strdup(username);
|
||||
if(!u_dup) return MOSQ_ERR_NOMEM;
|
||||
}else{
|
||||
|
@ -103,6 +103,7 @@ int property__process_will(struct mosquitto *context, struct mosquitto_message_a
|
||||
break;
|
||||
|
||||
default:
|
||||
msg->properties = msg_properties;
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
break;
|
||||
}
|
||||
|
20
src/retain.c
20
src/retain.c
@ -72,6 +72,25 @@ int retain__init(void)
|
||||
}
|
||||
|
||||
|
||||
void retain__clean_empty_hierarchy(struct mosquitto__retainhier *retainhier)
|
||||
{
|
||||
struct mosquitto__retainhier *parent;
|
||||
|
||||
while(retainhier){
|
||||
if(retainhier->children || retainhier->retained || retainhier->parent == NULL){
|
||||
/* Entry is being used */
|
||||
return;
|
||||
}else{
|
||||
HASH_DELETE(hh, retainhier->parent->children, retainhier);
|
||||
mosquitto__free(retainhier->topic);
|
||||
parent = retainhier->parent;
|
||||
mosquitto__free(retainhier);
|
||||
retainhier = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int retain__store(const char *topic, struct mosquitto_msg_store *stored, char **split_topics)
|
||||
{
|
||||
struct mosquitto__retainhier *retainhier;
|
||||
@ -124,6 +143,7 @@ int retain__store(const char *topic, struct mosquitto_msg_store *stored, char **
|
||||
#endif
|
||||
}else{
|
||||
retainhier->retained = NULL;
|
||||
retain__clean_empty_hierarchy(retainhier);
|
||||
}
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
|
@ -530,7 +530,7 @@ static int aclfile__parse(struct mosquitto__security_options *security_opts)
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
|
||||
aclfptr = mosquitto__fopen(security_opts->acl_file, "rt", false);
|
||||
aclfptr = mosquitto__fopen(security_opts->acl_file, "rt", true);
|
||||
if(!aclfptr){
|
||||
mosquitto__free(buf);
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open acl_file \"%s\".", security_opts->acl_file);
|
||||
@ -755,7 +755,7 @@ static int pwfile__parse(const char *file, struct mosquitto__unpwd **root)
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
|
||||
pwfile = mosquitto__fopen(file, "rt", false);
|
||||
pwfile = mosquitto__fopen(file, "rt", true);
|
||||
if(!pwfile){
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open pwfile \"%s\".", file);
|
||||
mosquitto__free(buf);
|
||||
@ -980,9 +980,7 @@ static int mosquitto__memcmp_const(const void *a, const void *b, size_t len)
|
||||
if(!a || !b) return 1;
|
||||
|
||||
for(i=0; i<len; i++){
|
||||
if( ((char *)a)[i] != ((char *)b)[i] ){
|
||||
rc = 1;
|
||||
}
|
||||
rc |= ((char *)a)[i] ^ ((char *)b)[i];
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -43,6 +43,26 @@ static int session_expiry__cmp(struct session_expiry_list *i1, struct session_ex
|
||||
}
|
||||
|
||||
|
||||
static void set_session_expiry_time(struct mosquitto *context)
|
||||
{
|
||||
context->session_expiry_time = db.now_real_s;
|
||||
|
||||
if(db.config->persistent_client_expiration == 0){
|
||||
/* No global expiry, so use the client expiration interval */
|
||||
context->session_expiry_time += context->session_expiry_interval;
|
||||
}else{
|
||||
/* We have a global expiry interval */
|
||||
if(db.config->persistent_client_expiration < context->session_expiry_interval){
|
||||
/* The client expiry is longer than the global expiry, so use the global */
|
||||
context->session_expiry_time += db.config->persistent_client_expiration;
|
||||
}else{
|
||||
/* The global expiry is longer than the client expiry, so use the client */
|
||||
context->session_expiry_time += context->session_expiry_interval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int session_expiry__add(struct mosquitto *context)
|
||||
{
|
||||
struct session_expiry_list *item;
|
||||
@ -59,21 +79,7 @@ int session_expiry__add(struct mosquitto *context)
|
||||
if(!item) return MOSQ_ERR_NOMEM;
|
||||
|
||||
item->context = context;
|
||||
item->context->session_expiry_time = db.now_real_s;
|
||||
|
||||
if(db.config->persistent_client_expiration == 0){
|
||||
/* No global expiry, so use the client expiration interval */
|
||||
item->context->session_expiry_time += item->context->session_expiry_interval;
|
||||
}else{
|
||||
/* We have a global expiry interval */
|
||||
if(db.config->persistent_client_expiration < item->context->session_expiry_interval){
|
||||
/* The client expiry is longer than the global expiry, so use the global */
|
||||
item->context->session_expiry_time += db.config->persistent_client_expiration;
|
||||
}else{
|
||||
/* The global expiry is longer than the client expiry, so use the client */
|
||||
item->context->session_expiry_time += item->context->session_expiry_interval;
|
||||
}
|
||||
}
|
||||
set_session_expiry_time(item->context);
|
||||
context->expiry_list_item = item;
|
||||
|
||||
DL_INSERT_INORDER(expiry_list, item, session_expiry__cmp);
|
||||
@ -98,7 +104,12 @@ int session_expiry__add_from_persistence(struct mosquitto *context, time_t expir
|
||||
if(!item) return MOSQ_ERR_NOMEM;
|
||||
|
||||
item->context = context;
|
||||
item->context->session_expiry_time = expiry_time;
|
||||
if(expiry_time){
|
||||
item->context->session_expiry_time = expiry_time;
|
||||
}else{
|
||||
set_session_expiry_time(item->context);
|
||||
|
||||
}
|
||||
context->expiry_list_item = item;
|
||||
|
||||
DL_INSERT_INORDER(expiry_list, item, session_expiry__cmp);
|
||||
@ -165,4 +176,3 @@ void session_expiry__check(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -389,6 +389,7 @@ static int sub__remove_normal(struct mosquitto *context, struct mosquitto__subhi
|
||||
if(context->subs[i] && context->subs[i]->hier == subhier){
|
||||
mosquitto__free(context->subs[i]);
|
||||
context->subs[i] = NULL;
|
||||
context->sub_count--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -429,6 +430,7 @@ static int sub__remove_shared(struct mosquitto *context, struct mosquitto__subhi
|
||||
|
||||
mosquitto__free(context->subs[i]);
|
||||
context->subs[i] = NULL;
|
||||
context->sub_count--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ Contributors:
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "mosquitto_broker_internal.h"
|
||||
#include "memory_mosq.h"
|
||||
@ -76,31 +77,31 @@ static void sys_tree__update_clients(char *buf)
|
||||
if(client_count != count_total){
|
||||
client_count = count_total;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%d", client_count);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/clients/total", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/clients/total", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
|
||||
if(client_count > client_max){
|
||||
client_max = client_count;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%d", client_max);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/clients/maximum", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/clients/maximum", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if(disconnected_count != count_total-count_by_sock){
|
||||
disconnected_count = count_total-count_by_sock;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%d", disconnected_count);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/clients/inactive", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/clients/disconnected", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/clients/inactive", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/clients/disconnected", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
}
|
||||
if(connected_count != count_by_sock){
|
||||
connected_count = count_by_sock;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%d", connected_count);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/clients/active", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/clients/connected", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/clients/active", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/clients/connected", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
}
|
||||
if(g_clients_expired != clients_expired){
|
||||
clients_expired = g_clients_expired;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%d", clients_expired);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/clients/expired", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/clients/expired", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,13 +117,13 @@ static void sys_tree__update_memory(char *buf)
|
||||
if(current_heap != value_ul){
|
||||
current_heap = value_ul;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%lu", current_heap);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/heap/current", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/heap/current", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
}
|
||||
value_ul =mosquitto__max_memory_used();
|
||||
if(max_heap != value_ul){
|
||||
max_heap = value_ul;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%lu", max_heap);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/heap/maximum", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/heap/maximum", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -135,12 +136,12 @@ static void calc_load(char *buf, const char *topic, bool initial, double exponen
|
||||
if (initial) {
|
||||
new_value = *current;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%.2f", new_value);
|
||||
db__messages_easy_queue(NULL, topic, SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, topic, SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
} else {
|
||||
new_value = interval + exponent*((*current) - interval);
|
||||
if(fabs(new_value - (*current)) >= 0.01){
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%.2f", new_value);
|
||||
db__messages_easy_queue(NULL, topic, SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, topic, SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
}
|
||||
}
|
||||
(*current) = new_value;
|
||||
@ -217,8 +218,8 @@ void sys_tree__update(int interval, time_t start_time)
|
||||
|
||||
if(interval && db.now_s - interval > last_update){
|
||||
uptime = db.now_s - start_time;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%d seconds", (int)uptime);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/uptime", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%" PRIu64 " seconds", (uint64_t)uptime);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/uptime", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
|
||||
sys_tree__update_clients(buf);
|
||||
initial_publish = false;
|
||||
@ -287,32 +288,32 @@ void sys_tree__update(int interval, time_t start_time)
|
||||
if(db.msg_store_count != msg_store_count){
|
||||
msg_store_count = db.msg_store_count;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%d", msg_store_count);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/messages/stored", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/store/messages/count", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/messages/stored", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/store/messages/count", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
}
|
||||
|
||||
if (db.msg_store_bytes != msg_store_bytes){
|
||||
msg_store_bytes = db.msg_store_bytes;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%lu", msg_store_bytes);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/store/messages/bytes", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/store/messages/bytes", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
}
|
||||
|
||||
if(db.subscription_count != subscription_count){
|
||||
subscription_count = db.subscription_count;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%d", subscription_count);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/subscriptions/count", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/subscriptions/count", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
}
|
||||
|
||||
if(db.shared_subscription_count != shared_subscription_count){
|
||||
shared_subscription_count = db.shared_subscription_count;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%d", shared_subscription_count);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/shared_subscriptions/count", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/shared_subscriptions/count", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
}
|
||||
|
||||
if(db.retained_count != retained_count){
|
||||
retained_count = db.retained_count;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%d", retained_count);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/retained messages/count", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/retained messages/count", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
}
|
||||
|
||||
#ifdef REAL_WITH_MEMORY_TRACKING
|
||||
@ -322,55 +323,55 @@ void sys_tree__update(int interval, time_t start_time)
|
||||
if(msgs_received != g_msgs_received){
|
||||
msgs_received = g_msgs_received;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%lu", msgs_received);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/messages/received", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/messages/received", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
}
|
||||
|
||||
if(msgs_sent != g_msgs_sent){
|
||||
msgs_sent = g_msgs_sent;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%lu", msgs_sent);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/messages/sent", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/messages/sent", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
}
|
||||
|
||||
if(publish_dropped != g_msgs_dropped){
|
||||
publish_dropped = g_msgs_dropped;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%lu", publish_dropped);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/publish/messages/dropped", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/publish/messages/dropped", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
}
|
||||
|
||||
if(pub_msgs_received != g_pub_msgs_received){
|
||||
pub_msgs_received = g_pub_msgs_received;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%lu", pub_msgs_received);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/publish/messages/received", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/publish/messages/received", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
}
|
||||
|
||||
if(pub_msgs_sent != g_pub_msgs_sent){
|
||||
pub_msgs_sent = g_pub_msgs_sent;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%lu", pub_msgs_sent);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/publish/messages/sent", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/publish/messages/sent", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
}
|
||||
|
||||
if(bytes_received != g_bytes_received){
|
||||
bytes_received = g_bytes_received;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%llu", bytes_received);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/bytes/received", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/bytes/received", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
}
|
||||
|
||||
if(bytes_sent != g_bytes_sent){
|
||||
bytes_sent = g_bytes_sent;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%llu", bytes_sent);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/bytes/sent", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/bytes/sent", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
}
|
||||
|
||||
if(pub_bytes_received != g_pub_bytes_received){
|
||||
pub_bytes_received = g_pub_bytes_received;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%llu", pub_bytes_received);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/publish/bytes/received", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/publish/bytes/received", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
}
|
||||
|
||||
if(pub_bytes_sent != g_pub_bytes_sent){
|
||||
pub_bytes_sent = g_pub_bytes_sent;
|
||||
len = (uint32_t)snprintf(buf, BUFLEN, "%llu", pub_bytes_sent);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/publish/bytes/sent", SYS_TREE_QOS, len, buf, 1, 60, NULL);
|
||||
db__messages_easy_queue(NULL, "$SYS/broker/publish/bytes/sent", SYS_TREE_QOS, len, buf, 1, 0, NULL);
|
||||
}
|
||||
|
||||
last_update = db.now_s;
|
||||
|
81
test/broker/01-bad-initial-packets.py
Executable file
81
test/broker/01-bad-initial-packets.py
Executable file
@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Test whether non-CONNECT packets as an initial packet can cause excess memory use
|
||||
|
||||
from mosq_test_helper import *
|
||||
import psutil
|
||||
|
||||
def write_config(filename, port):
|
||||
with open(filename, 'w') as f:
|
||||
f.write(f"listener {port}\n")
|
||||
f.write("allow_anonymous true\n")
|
||||
f.write("sys_interval 1\n")
|
||||
|
||||
def do_send(port, socks, payload):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
socks.append(sock)
|
||||
sock.connect(("127.0.0.1", port))
|
||||
try:
|
||||
sock.send(payload)
|
||||
except ConnectionResetError:
|
||||
pass
|
||||
|
||||
def do_test(port):
|
||||
rc = 1
|
||||
|
||||
conf_file = os.path.basename(__file__).replace('.py', '.conf')
|
||||
write_config(conf_file, port)
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port, use_conf=True)
|
||||
|
||||
try:
|
||||
socks = []
|
||||
|
||||
do_send(port, socks, b"\x20\x80\x80\x80t" + b"\01"*100000000) # CONNACK
|
||||
do_send(port, socks, b"\x30\x80\x80\x80t" + b"\01"*100000000) # PUBLISH
|
||||
do_send(port, socks, b"\x40\x80\x80\x80t" + b"\01"*100000000) # PUBACK
|
||||
do_send(port, socks, b"\x50\x80\x80\x80t" + b"\01"*100000000) # PUBREC
|
||||
do_send(port, socks, b"\x60\x80\x80\x80t" + b"\01"*100000000) # PUBREL
|
||||
do_send(port, socks, b"\x70\x80\x80\x80t" + b"\01"*100000000) # PUBCOMP
|
||||
do_send(port, socks, b"\x80\x80\x80\x80t" + b"\01"*100000000) # SUBSCRIBE
|
||||
do_send(port, socks, b"\x90\x80\x80\x80t" + b"\01"*100000000) # SUBACK
|
||||
do_send(port, socks, b"\xA0\x80\x80\x80t" + b"\01"*100000000) # UNSUBSCRIBE
|
||||
do_send(port, socks, b"\xB0\x80\x80\x80t" + b"\01"*100000000) # UNSUBACK
|
||||
do_send(port, socks, b"\xC0\x80\x80\x80t" + b"\01"*100000000) # PINGREQ
|
||||
do_send(port, socks, b"\xD0\x80\x80\x80t" + b"\01"*100000000) # PINGRESP
|
||||
do_send(port, socks, b"\xE0\x80\x80\x80t" + b"\01"*100000000) # DISCONNECT
|
||||
do_send(port, socks, b"\xF0\x80\x80\x80t" + b"\01"*100000000) # AUTH
|
||||
|
||||
mem = psutil.Process(broker.pid).memory_info().vms
|
||||
|
||||
for s in socks:
|
||||
s.close()
|
||||
|
||||
if os.environ.get('MOSQ_USE_VALGRIND') is None:
|
||||
limit = 25000000
|
||||
else:
|
||||
limit = 120000000
|
||||
if mem > limit:
|
||||
raise mosq_test.TestError(f"Process memory {mem} greater than limit of {limit}")
|
||||
|
||||
rc = 0
|
||||
except MemoryError:
|
||||
print("Memory error!")
|
||||
except Exception as e:
|
||||
print(e)
|
||||
except mosq_test.TestError:
|
||||
pass
|
||||
finally:
|
||||
os.remove(conf_file)
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
(stdo, stde) = broker.communicate()
|
||||
if rc:
|
||||
print(stde.decode('utf-8'))
|
||||
exit(rc)
|
||||
|
||||
|
||||
port = mosq_test.get_port()
|
||||
|
||||
do_test(port)
|
||||
|
||||
exit(0)
|
58
test/broker/03-publish-qos2-dup.py
Executable file
58
test/broker/03-publish-qos2-dup.py
Executable file
@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from mosq_test_helper import *
|
||||
|
||||
def do_test(proto_ver):
|
||||
rc = 1
|
||||
connect_packet = mosq_test.gen_connect("03-pub-qos2-dup-test", proto_ver=proto_ver)
|
||||
connack_packet = mosq_test.gen_connack(rc=0, proto_ver=proto_ver)
|
||||
|
||||
mid = 1
|
||||
publish_packet = mosq_test.gen_publish("topic", qos=2, mid=mid, payload="message", proto_ver=proto_ver, dup=1)
|
||||
pubrec_packet = mosq_test.gen_pubrec(mid, proto_ver=proto_ver)
|
||||
|
||||
disconnect_packet = mosq_test.gen_disconnect(reason_code=130, proto_ver=proto_ver)
|
||||
|
||||
port = mosq_test.get_port()
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port)
|
||||
|
||||
try:
|
||||
sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port)
|
||||
mosq_test.do_send_receive(sock, publish_packet, pubrec_packet, "pubrec 1")
|
||||
mosq_test.do_send_receive(sock, publish_packet, pubrec_packet, "pubrec 2")
|
||||
if proto_ver == 5:
|
||||
mosq_test.do_send_receive(sock, publish_packet, disconnect_packet, "disconnect")
|
||||
rc = 0
|
||||
else:
|
||||
try:
|
||||
mosq_test.do_send_receive(sock, publish_packet, b"", "disconnect1")
|
||||
rc = 0
|
||||
except BrokenPipeError:
|
||||
rc = 0
|
||||
|
||||
sock.close()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
except mosq_test.TestError:
|
||||
pass
|
||||
finally:
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
(stdo, stde) = broker.communicate()
|
||||
if rc:
|
||||
print(stde.decode('utf-8'))
|
||||
print("proto_ver=%d" % (proto_ver))
|
||||
exit(rc)
|
||||
|
||||
|
||||
def all_tests():
|
||||
rc = do_test(proto_ver=4)
|
||||
if rc:
|
||||
return rc;
|
||||
rc = do_test(proto_ver=5)
|
||||
if rc:
|
||||
return rc;
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
all_tests()
|
80
test/broker/04-retain-clear-multiple.py
Executable file
80
test/broker/04-retain-clear-multiple.py
Executable file
@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Exercise multi-level retain clearing
|
||||
|
||||
from mosq_test_helper import *
|
||||
|
||||
def send_retain(port, topic, payload):
|
||||
connect_packet = mosq_test.gen_connect("retain-clear-test")
|
||||
connack_packet = mosq_test.gen_connack(rc=0)
|
||||
|
||||
publish_packet = mosq_test.gen_publish(topic, qos=1, mid=1, payload=payload, retain=True)
|
||||
puback_packet = mosq_test.gen_puback(mid=1)
|
||||
|
||||
sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=4, port=port)
|
||||
mosq_test.do_send_receive(sock, publish_packet, puback_packet, f"set retain {topic}")
|
||||
sock.close()
|
||||
|
||||
def do_test():
|
||||
rc = 1
|
||||
connect_packet = mosq_test.gen_connect("retain-clear-test")
|
||||
connack_packet = mosq_test.gen_connack(rc=0)
|
||||
|
||||
subscribe_packet = mosq_test.gen_subscribe(1, "#", 0)
|
||||
suback_packet = mosq_test.gen_suback(1, 0)
|
||||
|
||||
retain1_packet = mosq_test.gen_publish("1/2/3/4/5/6/7", qos=0, payload="retained message", retain=True)
|
||||
retain2_packet = mosq_test.gen_publish("1/2/3/4", qos=0, payload="retained message", retain=True)
|
||||
retain3_packet = mosq_test.gen_publish("1", qos=0, payload="retained message", retain=True)
|
||||
|
||||
port = mosq_test.get_port()
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port)
|
||||
|
||||
try:
|
||||
send_retain(port, "1/2/3/4/5/6/7", "retained message")
|
||||
send_retain(port, "1/2/3/4", "retained message")
|
||||
send_retain(port, "1", "retained message")
|
||||
|
||||
sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port)
|
||||
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback")
|
||||
mosq_test.expect_packet(sock, "retain3", retain3_packet)
|
||||
mosq_test.expect_packet(sock, "retain2", retain2_packet)
|
||||
mosq_test.expect_packet(sock, "retain1", retain1_packet)
|
||||
sock.close()
|
||||
|
||||
send_retain(port, "1/2/3/4", None)
|
||||
|
||||
sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port)
|
||||
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback")
|
||||
mosq_test.expect_packet(sock, "retain3", retain3_packet)
|
||||
mosq_test.expect_packet(sock, "retain1", retain1_packet)
|
||||
sock.close()
|
||||
|
||||
send_retain(port, "1/2/3/4/5/6/7", None)
|
||||
|
||||
sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port)
|
||||
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback")
|
||||
mosq_test.expect_packet(sock, "retain3", retain3_packet)
|
||||
sock.close()
|
||||
|
||||
send_retain(port, "1", None)
|
||||
|
||||
sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port)
|
||||
mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback")
|
||||
mosq_test.do_ping(sock)
|
||||
sock.close()
|
||||
|
||||
rc = 0
|
||||
except mosq_test.TestError:
|
||||
pass
|
||||
finally:
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
(stdo, stde) = broker.communicate()
|
||||
if rc:
|
||||
print(stde.decode('utf-8'))
|
||||
exit(rc)
|
||||
|
||||
do_test()
|
||||
exit(0)
|
||||
|
@ -17,6 +17,7 @@ def write_config(filename, port1, port2, protocol_version):
|
||||
f.write("address 127.0.0.1:%d\n" % (port1))
|
||||
f.write("topic bridge/# out\n")
|
||||
f.write("bridge_protocol_version %s\n" % (protocol_version))
|
||||
f.write("cleansession false\n")
|
||||
|
||||
|
||||
def do_test(proto_ver):
|
||||
|
51
test/broker/07-will-control.py
Executable file
51
test/broker/07-will-control.py
Executable file
@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Test whether a client setting a will with $CONTROL in is denied
|
||||
|
||||
from mosq_test_helper import *
|
||||
|
||||
|
||||
def do_test(start_broker, proto_ver):
|
||||
rc = 1
|
||||
mid = 1
|
||||
connect_packet = mosq_test.gen_connect("will", will_topic="$CONTROL/dynamic-security/v1", will_payload=b"will-message", proto_ver=proto_ver)
|
||||
|
||||
port = mosq_test.get_port()
|
||||
if start_broker:
|
||||
broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port)
|
||||
|
||||
try:
|
||||
sock = mosq_test.client_connect_only(port=port)
|
||||
sock.send(connect_packet)
|
||||
d = sock.recv(1)
|
||||
if d == b"":
|
||||
rc = 0
|
||||
|
||||
sock.close()
|
||||
except mosq_test.TestError:
|
||||
pass
|
||||
except Exception as e:
|
||||
print(e)
|
||||
finally:
|
||||
if start_broker:
|
||||
broker.terminate()
|
||||
broker.wait()
|
||||
(stdo, stde) = broker.communicate()
|
||||
if rc:
|
||||
print(stde.decode('utf-8'))
|
||||
exit(rc)
|
||||
else:
|
||||
return rc
|
||||
|
||||
|
||||
def all_tests(start_broker=False):
|
||||
rc = do_test(start_broker, proto_ver=4)
|
||||
if rc:
|
||||
return rc;
|
||||
rc = do_test(start_broker, proto_ver=5)
|
||||
if rc:
|
||||
return rc;
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
all_tests(True)
|
@ -23,6 +23,7 @@ msg_sequence_test:
|
||||
./msg_sequence_test.py
|
||||
|
||||
01 :
|
||||
./01-bad-initial-packets.py
|
||||
./01-connect-575314.py
|
||||
./01-connect-allow-anonymous.py
|
||||
./01-connect-disconnect-v5.py
|
||||
@ -83,6 +84,7 @@ msg_sequence_test:
|
||||
./03-publish-qos1-no-subscribers-v5.py
|
||||
./03-publish-qos1-retain-disabled.py
|
||||
./03-publish-qos1.py
|
||||
./03-publish-qos2-dup.py
|
||||
./03-publish-qos2-max-inflight.py
|
||||
./03-publish-qos2.py
|
||||
|
||||
@ -90,6 +92,7 @@ msg_sequence_test:
|
||||
./04-retain-check-source-persist-diff-port.py
|
||||
./04-retain-check-source-persist.py
|
||||
./04-retain-check-source.py
|
||||
./04-retain-clear-multiple.py
|
||||
./04-retain-qos0-clear.py
|
||||
./04-retain-qos0-fresh.py
|
||||
./04-retain-qos0-repeated.py
|
||||
@ -124,6 +127,7 @@ msg_sequence_test:
|
||||
./06-bridge-reconnect-local-out.py
|
||||
|
||||
07 :
|
||||
./07-will-control.py
|
||||
./07-will-delay-invalid-573191.py
|
||||
./07-will-delay-reconnect.py
|
||||
./07-will-delay-recover.py
|
||||
|
@ -5,6 +5,7 @@ import ptest
|
||||
|
||||
tests = [
|
||||
#(ports required, 'path'),
|
||||
(1, './01-bad-initial-packets.py'),
|
||||
(1, './01-connect-575314.py'),
|
||||
(1, './01-connect-allow-anonymous.py'),
|
||||
(1, './01-connect-disconnect-v5.py'),
|
||||
@ -63,11 +64,13 @@ tests = [
|
||||
(1, './03-publish-qos1-no-subscribers-v5.py'),
|
||||
(1, './03-publish-qos1-retain-disabled.py'),
|
||||
(1, './03-publish-qos1.py'),
|
||||
(1, './03-publish-qos2-dup.py'),
|
||||
(1, './03-publish-qos2-max-inflight.py'),
|
||||
(1, './03-publish-qos2.py'),
|
||||
|
||||
(1, './04-retain-check-source-persist.py'),
|
||||
(1, './04-retain-check-source.py'),
|
||||
(1, './04-retain-clear-multiple.py'),
|
||||
(1, './04-retain-qos0-clear.py'),
|
||||
(1, './04-retain-qos0-fresh.py'),
|
||||
(1, './04-retain-qos0-repeated.py'),
|
||||
@ -100,6 +103,7 @@ tests = [
|
||||
(3, './06-bridge-per-listener-settings.py'),
|
||||
(2, './06-bridge-reconnect-local-out.py'),
|
||||
|
||||
(1, './07-will-control.py'),
|
||||
(1, './07-will-delay-invalid-573191.py'),
|
||||
(1, './07-will-delay-reconnect.py'),
|
||||
(1, './07-will-delay-recover.py'),
|
||||
|
@ -70,7 +70,7 @@ def start_broker(filename, cmd=None, port=0, use_conf=False, expect_fail=False,
|
||||
print("FAIL: unable to start broker: %s" % errs)
|
||||
raise IOError
|
||||
else:
|
||||
return None
|
||||
return broker
|
||||
|
||||
def start_client(filename, cmd, env, port=1888):
|
||||
if cmd is None:
|
||||
|
@ -82,6 +82,10 @@ PERSIST_WRITE_OBJS = \
|
||||
utf8_mosq.o \
|
||||
util_mosq.o
|
||||
|
||||
TLS_TEST_OBJS = \
|
||||
tls_test.o \
|
||||
tls_stubs.o
|
||||
|
||||
SUBS_TEST_OBJS = \
|
||||
subs_test.o \
|
||||
subs_stubs.o
|
||||
@ -112,6 +116,9 @@ persist_write_test : ${PERSIST_WRITE_TEST_OBJS} ${PERSIST_WRITE_OBJS}
|
||||
subs_test : ${SUBS_TEST_OBJS} ${SUBS_OBJS}
|
||||
$(CROSS_COMPILE)$(CC) $(LDFLAGS) -o $@ $^ $(LDADD)
|
||||
|
||||
tls_test : ${TLS_TEST_OBJS} ${TLS_OBJS}
|
||||
$(CROSS_COMPILE)$(CC) $(LDFLAGS) -o $@ $^ $(LDADD) -lssl -lcrypto
|
||||
|
||||
|
||||
bridge_topic.o : ../../src/bridge_topic.c
|
||||
$(CROSS_COMPILE)$(CC) $(CPPFLAGS) $(CFLAGS) -DWITH_BROKER -DWITH_BRIDGE -c -o $@ $^
|
||||
@ -167,10 +174,11 @@ util_topic.o : ../../lib/util_topic.c
|
||||
utf8_mosq.o : ../../lib/utf8_mosq.c
|
||||
$(CROSS_COMPILE)$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
build : mosq_test bridge_topic_test persist_read_test persist_write_test subs_test
|
||||
build : mosq_test bridge_topic_test persist_read_test persist_write_test subs_test tls_test
|
||||
|
||||
test-lib : build
|
||||
./mosq_test
|
||||
./tls_test
|
||||
|
||||
test-broker : build
|
||||
./bridge_topic_test
|
||||
|
40
test/unit/tls_stubs.c
Normal file
40
test/unit/tls_stubs.c
Normal file
@ -0,0 +1,40 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <logging_mosq.h>
|
||||
|
||||
int tls_ex_index_mosq;
|
||||
|
||||
struct mosquitto_db{
|
||||
|
||||
};
|
||||
|
||||
int log__printf(struct mosquitto *mosq, unsigned int priority, const char *fmt, ...)
|
||||
{
|
||||
UNUSED(mosq);
|
||||
UNUSED(priority);
|
||||
UNUSED(fmt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
time_t mosquitto_time(void)
|
||||
{
|
||||
return 123;
|
||||
}
|
||||
|
||||
int net__socket_close(struct mosquitto_db *db, struct mosquitto *mosq)
|
||||
{
|
||||
UNUSED(db);
|
||||
UNUSED(mosq);
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int send__pingreq(struct mosquitto *mosq)
|
||||
{
|
||||
UNUSED(mosq);
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
102
test/unit/tls_test.c
Normal file
102
test/unit/tls_test.c
Normal file
@ -0,0 +1,102 @@
|
||||
#include <CUnit/CUnit.h>
|
||||
#include <CUnit/Basic.h>
|
||||
|
||||
#define WITH_TLS
|
||||
|
||||
#include "tls_mosq.c"
|
||||
|
||||
//static int mosquitto__cmp_hostname_wildcard(char *certname, const char *hostname)
|
||||
|
||||
void hostname_cmp_helper(char *certname, const char *hostname, int expected)
|
||||
{
|
||||
int rc = mosquitto__cmp_hostname_wildcard(certname, hostname);
|
||||
CU_ASSERT_EQUAL(rc, expected);
|
||||
if(rc != expected){
|
||||
printf("%d || %d\n", rc, expected);
|
||||
}
|
||||
}
|
||||
|
||||
void TEST_tls_hostname_compare_null(void)
|
||||
{
|
||||
hostname_cmp_helper(NULL, "localhost", 1);
|
||||
hostname_cmp_helper("localhost", NULL, 1);
|
||||
hostname_cmp_helper(NULL, NULL, 1);
|
||||
}
|
||||
|
||||
|
||||
void TEST_tls_hostname_compare_simple(void)
|
||||
{
|
||||
hostname_cmp_helper("localhost", "localhost", 0);
|
||||
hostname_cmp_helper("localhost", "localhose", 15);
|
||||
}
|
||||
|
||||
|
||||
void TEST_tls_hostname_compare_bad_wildcard_format(void)
|
||||
{
|
||||
hostname_cmp_helper("**localhost", "localhost", 1);
|
||||
hostname_cmp_helper("*,localhost", "localhost", 1);
|
||||
hostname_cmp_helper("*.", "localhost", 1);
|
||||
}
|
||||
|
||||
|
||||
void TEST_tls_hostname_compare_invalid_wildcard(void)
|
||||
{
|
||||
hostname_cmp_helper("*.com", "example.com", 1);
|
||||
hostname_cmp_helper("*.com", "example.org", 1);
|
||||
hostname_cmp_helper("*.org", "example.org", 1);
|
||||
}
|
||||
|
||||
|
||||
void TEST_tls_hostname_compare_good_wildcard(void)
|
||||
{
|
||||
hostname_cmp_helper("*.example.com", "test.example.com", 0);
|
||||
hostname_cmp_helper("*.example.com", "test.example.org", -12);
|
||||
hostname_cmp_helper("*.example.org", "test.example.org", 0);
|
||||
}
|
||||
|
||||
|
||||
/* ========================================================================
|
||||
* TEST SUITE SETUP
|
||||
* ======================================================================== */
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
CU_pSuite test_suite = NULL;
|
||||
unsigned int fails;
|
||||
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
|
||||
if(CU_initialize_registry() != CUE_SUCCESS){
|
||||
printf("Error initializing CUnit registry.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
test_suite = CU_add_suite("Subs", NULL, NULL);
|
||||
if(!test_suite){
|
||||
printf("Error adding CUnit TLS test suite.\n");
|
||||
CU_cleanup_registry();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(0
|
||||
|| !CU_add_test(test_suite, "TLS hostname compare null", TEST_tls_hostname_compare_null)
|
||||
|| !CU_add_test(test_suite, "TLS hostname compare simple", TEST_tls_hostname_compare_simple)
|
||||
|| !CU_add_test(test_suite, "TLS hostname compare bad wildcard format", TEST_tls_hostname_compare_bad_wildcard_format)
|
||||
|| !CU_add_test(test_suite, "TLS hostname compare invalid wildcard", TEST_tls_hostname_compare_invalid_wildcard)
|
||||
|| !CU_add_test(test_suite, "TLS hostname compare good wildcard", TEST_tls_hostname_compare_good_wildcard)
|
||||
){
|
||||
|
||||
printf("Error adding TLS CUnit tests.\n");
|
||||
CU_cleanup_registry();
|
||||
return 1;
|
||||
}
|
||||
|
||||
CU_basic_set_mode(CU_BRM_VERBOSE);
|
||||
CU_basic_run_tests();
|
||||
fails = CU_get_number_of_failures();
|
||||
CU_cleanup_registry();
|
||||
|
||||
return (int)fails;
|
||||
}
|
@ -415,10 +415,10 @@ void TEST_utf8_control_characters(void)
|
||||
buf[1] = '\0';
|
||||
utf8_helper((char *)buf, MOSQ_ERR_MALFORMED_UTF8);
|
||||
|
||||
/* U+007F to U+009F are two byte control characters */
|
||||
/* U+0080 to U+009F are two byte control characters */
|
||||
for(i=0x80; i<0xA0; i++){
|
||||
buf[0] = 0xC2;
|
||||
buf[1] = (uint8_t)(i-0x80);
|
||||
buf[1] = (uint8_t)i;
|
||||
buf[2] = '\0';
|
||||
utf8_helper((char *)buf, MOSQ_ERR_MALFORMED_UTF8);
|
||||
}
|
||||
|
@ -19,6 +19,9 @@ follow the steps on [Eclipse Security] page to report it.
|
||||
Listed with most recent first. Further information on security related issues
|
||||
can be found in the [security category].
|
||||
|
||||
* June 2023: [CVE-2023-28366]: Clients sending unacknowledged QoS 2 messages
|
||||
with duplicate message ids cause a memory leak. Affecting versions **1.3.2**
|
||||
to **2.0.15** inclusive, fixed in **2.0.16**.
|
||||
* August 2022: Deleting the anonymous group in the dynamic security plugin
|
||||
could lead to a crash. Affecting versions **2.0.0** to **2.0.14** inclusive,
|
||||
fixed in **2.0.15**.
|
||||
@ -62,14 +65,14 @@ can be found in the [security category].
|
||||
inclusive, fixed in **1.4.12**. More details at
|
||||
[security-advisory-cve-2017-7650].
|
||||
|
||||
[version-166-released]: /2019/09/version-1-6-6-released/
|
||||
[version-162-released]: /2019/04/version-1-6-2-released/
|
||||
[version-155-released]: /2018/11/version-155-released/
|
||||
[version-154-released]: /2018/11/version-154-released/
|
||||
[security-advisory-cve-2018-12543]: /2018/09/security-advisory-cve-2018-12543/
|
||||
[security-advisory-cve-2017-7651-cve-2017-7652]: /2018/02/security-advisory-cve-2017-7651-cve-2017-7652/
|
||||
[security-advisory-cve-2017-7650]: /2017/05/security-advisory-cve-2017-7650/
|
||||
[security-advisory-cve-2017-9868]: /2017/06/security-advisory-cve-2017-9868/
|
||||
[version-166-released]: /blog/2019/09/version-1-6-6-released/
|
||||
[version-162-released]: /blog/2019/04/version-1-6-2-released/
|
||||
[version-155-released]: /blog/2018/11/version-155-released/
|
||||
[version-154-released]: /blog/2018/11/version-154-released/
|
||||
[security-advisory-cve-2018-12543]: /blog/2018/09/security-advisory-cve-2018-12543/
|
||||
[security-advisory-cve-2017-7651-cve-2017-7652]: /blog/2018/02/security-advisory-cve-2017-7651-cve-2017-7652/
|
||||
[security-advisory-cve-2017-7650]: /blog/2017/05/security-advisory-cve-2017-7650/
|
||||
[security-advisory-cve-2017-9868]: /blog/2017/06/security-advisory-cve-2017-9868/
|
||||
|
||||
[Eclipse Security]: https://www.eclipse.org/security/
|
||||
[security category]: /blog/categories/security/
|
||||
@ -81,9 +84,9 @@ can be found in the [security category].
|
||||
[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
|
||||
[CVE-2017-7654]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7652
|
||||
[CVE-2017-7653]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7652
|
||||
[CVE-2017-7655]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7655
|
||||
[CVE-2017-7654]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7654
|
||||
[CVE-2017-7653]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7653
|
||||
[CVE-2017-7652]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7652
|
||||
[CVE-2017-7651]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7651
|
||||
[CVE-2017-7650]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7650
|
||||
|
@ -17,13 +17,14 @@ Then use the following for your mosquitto.conf:
|
||||
|
||||
```
|
||||
listener 8883
|
||||
cafile /etc/ssl/certs/DST_Root_CA_X3.pem
|
||||
cafile /etc/ssl/certs/ISRG_Root_X1.pem
|
||||
certfile /etc/letsencrypt/live/example.com/fullchain.pem
|
||||
keyfile /etc/letsencrypt/live/example.com/privkey.pem
|
||||
```
|
||||
|
||||
You need to be aware that current versions of mosquitto never update listener
|
||||
settings when running, so when you regenerate the server certificates you will
|
||||
need to completely restart the broker.
|
||||
Since version 2.0 of Mosquitto, you can send a SIGHUP to the broker to cause it
|
||||
to reload certificates. Prior to this version, mosquitto would never update
|
||||
listener settings when running, so you will need to completely restart the
|
||||
broker.
|
||||
|
||||
[Let's Encrypt]: https://letsencrypt.org/
|
||||
|
Loading…
x
Reference in New Issue
Block a user