Move password functions to libcommon.

This commit is contained in:
Roger A. Light
2024-06-12 21:26:25 +01:00
committed by Roger Light
parent c9d930fb74
commit b5e21d146d
39 changed files with 607 additions and 549 deletions
+1 -1
View File
@@ -45,4 +45,4 @@ jobs:
-
name: make test
run: |
make WITH_ASAN=yes ptest
make WITH_ASAN=yes test
+2 -2
View File
@@ -40,8 +40,8 @@ jobs:
submodules: 'true'
-
name: make
run: make ALLOC_MISMATCH_ABORT=yes
run: make
-
name: make test
run: |
make ALLOC_MISMATCH_ABORT=yes ptest
make test
-8
View File
@@ -10,7 +10,6 @@ if(WITH_TLS)
../mosquitto_passwd/get_password.c ../mosquitto_passwd/get_password.h
options.c
../../common/json_help.c ../../common/json_help.h
../../common/password_mosq.c ../../common/password_mosq.h
)
target_include_directories(mosquitto_ctrl PRIVATE
@@ -46,13 +45,6 @@ if(WITH_TLS)
endif()
endif()
if(ARGON2_FOUND)
target_link_libraries(mosquitto_ctrl
PRIVATE
argon2
)
endif()
target_link_libraries(mosquitto_ctrl
PRIVATE
common-options
+2 -6
View File
@@ -6,7 +6,7 @@ include ${R}/config.mk
LOCAL_CFLAGS+=
LOCAL_CPPFLAGS+=-I${R}/lib -I${R}/apps/mosquitto_passwd -I${R}/plugins/dynamic-security -I${R}/common
LOCAL_LDFLAGS+=
LOCAL_LDADD+=-lcjson -ldl ${LIBMOSQ} ${LIBMOSQ_COMMON} ${LIB_ARGON2}
LOCAL_LDADD+=-lcjson -ldl ${LIBMOSQ} ${LIBMOSQ_COMMON}
# ------------------------------------------
# Compile time options
@@ -34,8 +34,7 @@ OBJS= \
OBJS_EXTERNAL= \
get_password.o \
json_help.o \
password_mosq.o
json_help.o
EXAMPLE_OBJS= example.o
@@ -65,9 +64,6 @@ get_password.o : ${R}/apps/mosquitto_passwd/get_password.c ${R}/apps/mosquitto_p
json_help.o : ${R}/common/json_help.c ${R}/common/json_help.h
${CROSS_COMPILE}${CC} $(LOCAL_CPPFLAGS) $(LOCAL_CFLAGS) -c $< -o $@
password_mosq.o : ${R}/common/password_mosq.c ${R}/common/password_mosq.h
${CROSS_COMPILE}${CC} $(LOCAL_CPPFLAGS) $(LOCAL_CFLAGS) -c $< -o $@
${R}/lib/libmosquitto.so.${SOVERSION} :
$(MAKE) -C ${R}/lib
+10 -33
View File
@@ -33,7 +33,6 @@ Contributors:
#include "mosquitto_ctrl.h"
#include "mosquitto.h"
#include "json_help.h"
#include "password_mosq.h"
#include "get_password.h"
#define MAX_STRING_LEN 4096
@@ -561,16 +560,16 @@ static cJSON *init_add_role(const char *rolename)
static cJSON *init_add_client(const char *username, const char *password, const char *rolename)
{
cJSON *j_client, *j_roles, *j_role;
struct mosquitto_pw pw;
struct mosquitto_pw *pw;
memset(&pw, 0, sizeof(pw));
if(pw__create(&pw, password) != MOSQ_ERR_SUCCESS){
if(mosquitto_pw_new(&pw, MOSQ_PW_DEFAULT) || mosquitto_pw_hash_encoded(pw, password)){
mosquitto_pw_cleanup(pw);
return NULL;
}
j_client = cJSON_CreateObject();
if(j_client == NULL){
mosquitto_pw_cleanup(pw);
return NULL;
}
@@ -579,38 +578,16 @@ static cJSON *init_add_client(const char *username, const char *password, const
){
cJSON_Delete(j_client);
mosquitto_pw_cleanup(pw);
return NULL;
}
if(pw.hashtype == pw_sha512_pbkdf2){
char *salt_b64 = NULL, *password_b64 = NULL;
if(mosquitto_base64_encode(pw.params.sha512_pbkdf2.salt, pw.params.sha512_pbkdf2.salt_len, &salt_b64)
|| mosquitto_base64_encode(pw.params.sha512_pbkdf2.password_hash, sizeof(pw.params.sha512_pbkdf2.password_hash), &password_b64)
|| cJSON_AddStringToObject(j_client, "salt", salt_b64) == NULL
|| cJSON_AddStringToObject(j_client, "password", password_b64) == NULL
|| cJSON_AddNumberToObject(j_client, "iterations", pw.params.sha512_pbkdf2.iterations) == NULL){
cJSON_Delete(j_client);
free(password_b64);
free(salt_b64);
return NULL;
}
free(password_b64);
free(salt_b64);
}else{
if(pw__encode(&pw) != MOSQ_ERR_SUCCESS){
cJSON_Delete(j_client);
return NULL;
}
if(cJSON_AddStringToObject(j_client, "encoded_password", pw.encoded_password) == NULL){
free(pw.encoded_password);
cJSON_Delete(j_client);
return NULL;
}
free(pw.encoded_password);
if(cJSON_AddStringToObject(j_client, "encoded_password", mosquitto_pw_get_encoded(pw)) == NULL){
cJSON_Delete(j_client);
mosquitto_pw_cleanup(pw);
return NULL;
}
mosquitto_pw_cleanup(pw);
j_roles = cJSON_CreateArray();
if(j_roles == NULL){
+25 -64
View File
@@ -24,7 +24,6 @@ Contributors:
#include "mosquitto_ctrl.h"
#include "get_password.h"
#include "json_help.h"
#include "password_mosq.h"
#include "dynamic_security.h"
int dynsec_client__create(int argc, char *argv[], cJSON *j_command)
@@ -161,6 +160,7 @@ int dynsec_client__file_set_password(int argc, char *argv[], const char *file)
struct dynsec__client client;
char *json_str;
int i;
int iterations = -1;
memset(&client, 0, sizeof(client));
@@ -176,7 +176,7 @@ int dynsec_client__file_set_password(int argc, char *argv[], const char *file)
fprintf(stderr, "Error: -i argument given, but no iterations provided.\n");
return MOSQ_ERR_INVAL;
}
client.pw.params.sha512_pbkdf2.iterations = atoi(argv[i+1]);
iterations = atoi(argv[i+1]);
i++;
}else{
fprintf(stderr, "Error: Unknown argument: %s\n", argv[i]);
@@ -231,89 +231,50 @@ int dynsec_client__file_set_password(int argc, char *argv[], const char *file)
const char *username_json;
if(json_get_string(j_client, "username", &username_json, false) == MOSQ_ERR_SUCCESS){
if(!strcmp(username_json, username)){
if(pw__create(&client.pw, password)){
if(iterations == -1){
mosquitto_pw_new(&client.pw, MOSQ_PW_DEFAULT);
}else{
mosquitto_pw_new(&client.pw, MOSQ_PW_SHA512_PBKDF2);
mosquitto_pw_set_param(client.pw, MOSQ_PW_PARAM_ITERATIONS, iterations);
}
if(!client.pw || mosquitto_pw_hash_encoded(client.pw, password)){
cJSON_Delete(j_tree);
mosquitto_pw_cleanup(client.pw);
client.pw = NULL;
fprintf(stderr, "Error: Problem generating password hash.\n");
return MOSQ_ERR_NOMEM;
}
if(client.pw.hashtype == pw_sha512_pbkdf2){
char *password_b64, *salt_b64;
cJSON *j_password = NULL, *j_salt = NULL, *j_iterations = NULL;
if(mosquitto_base64_encode(client.pw.params.sha512_pbkdf2.password_hash, sizeof(client.pw.params.sha512_pbkdf2.password_hash), &password_b64) != MOSQ_ERR_SUCCESS){
fprintf(stderr, "Error: Problem generating password hash.\n");
pw__cleanup(&client.pw);
return MOSQ_ERR_NOMEM;
}
if(mosquitto_base64_encode(client.pw.params.sha512_pbkdf2.salt, client.pw.params.sha512_pbkdf2.salt_len, &salt_b64) != MOSQ_ERR_SUCCESS){
pw__cleanup(&client.pw);
free(password_b64);
fprintf(stderr, "Error: Problem generating password hash.\n");
return MOSQ_ERR_NOMEM;
}
if((j_password = cJSON_CreateString(password_b64)) == NULL
|| (j_salt = cJSON_CreateString(salt_b64)) == NULL
|| (j_iterations = cJSON_CreateNumber(client.pw.params.sha512_pbkdf2.iterations)) == NULL
){
pw__cleanup(&client.pw);
free(password_b64);
free(salt_b64);
fprintf(stderr, "Error: Out of memory.\n");
return MOSQ_ERR_NOMEM;
}
free(password_b64);
free(salt_b64);
cJSON_DeleteItemFromObject(j_client, "password");
cJSON_DeleteItemFromObject(j_client, "salt");
cJSON_DeleteItemFromObject(j_client, "iterations");
cJSON_DeleteItemFromObject(j_client, "encoded_password");
cJSON_AddItemToObject(j_client, "password", j_password);
cJSON_AddItemToObject(j_client, "salt", j_salt);
cJSON_AddItemToObject(j_client, "iterations", j_iterations);
j_password = NULL;
j_salt = NULL;
j_iterations = NULL;
}else{
if(pw__encode(&client.pw)){
fprintf(stderr, "Error: Out of memory.\n");
pw__cleanup(&client.pw);
return MOSQ_ERR_NOMEM;
}
cJSON *j_encoded_password = cJSON_CreateString(client.pw.encoded_password);
if(!j_encoded_password){
fprintf(stderr, "Error: Out of memory.\n");
pw__cleanup(&client.pw);
return MOSQ_ERR_NOMEM;
}
cJSON_DeleteItemFromObject(j_client, "password");
cJSON_DeleteItemFromObject(j_client, "salt");
cJSON_DeleteItemFromObject(j_client, "iterations");
cJSON_DeleteItemFromObject(j_client, "encoded_password");
cJSON_AddItemToObject(j_client, "encoded_password", j_encoded_password);
cJSON *j_encoded_password = cJSON_CreateString(mosquitto_pw_get_encoded(client.pw));
if(!j_encoded_password){
fprintf(stderr, "Error: Out of memory.\n");
cJSON_Delete(j_tree);
mosquitto_pw_cleanup(client.pw);
return MOSQ_ERR_NOMEM;
}
mosquitto_pw_cleanup(client.pw);
cJSON_DeleteItemFromObject(j_client, "password");
cJSON_DeleteItemFromObject(j_client, "salt");
cJSON_DeleteItemFromObject(j_client, "iterations");
cJSON_DeleteItemFromObject(j_client, "encoded_password");
cJSON_AddItemToObject(j_client, "encoded_password", j_encoded_password);
json_str = cJSON_Print(j_tree);
cJSON_Delete(j_tree);
if(json_str == NULL){
fprintf(stderr, "Error: Out of memory.\n");
pw__cleanup(&client.pw);
return MOSQ_ERR_NOMEM;
}
fptr = fopen(file, "wb");
if(fptr == NULL){
fprintf(stderr, "Error: Unable to write to %s.\n", file);
free(json_str);
pw__cleanup(&client.pw);
return MOSQ_ERR_UNKNOWN;
}
fprintf(fptr, "%s", json_str);
free(json_str);
fclose(fptr);
pw__cleanup(&client.pw);
return MOSQ_ERR_SUCCESS;
}
}
-1
View File
@@ -25,7 +25,6 @@ Contributors:
#include "mosquitto.h"
#include "mosquitto_ctrl.h"
#include "json_help.h"
#include "password_mosq.h"
int dynsec_group__create(int argc, char *argv[], cJSON *j_command)
{
-1
View File
@@ -29,7 +29,6 @@ Contributors:
#include "mosquitto.h"
#include "mosquitto_ctrl.h"
#include "json_help.h"
#include "password_mosq.h"
int dynsec_role__create(int argc, char *argv[], cJSON *j_command)
{
-8
View File
@@ -2,7 +2,6 @@ if(WITH_TLS)
add_executable(mosquitto_passwd
mosquitto_passwd.c
get_password.c get_password.h
../../common/password_mosq.c ../../common/password_mosq.h
)
target_include_directories(mosquitto_passwd PRIVATE
@@ -13,13 +12,6 @@ if(WITH_TLS)
"${mosquitto_SOURCE_DIR}/src"
)
if(ARGON2_FOUND)
target_link_libraries(mosquitto_passwd
PRIVATE
argon2
)
endif()
target_link_libraries(mosquitto_passwd
PRIVATE
common-options
+2 -6
View File
@@ -4,7 +4,7 @@ include ${R}/config.mk
LOCAL_CFLAGS+=
LOCAL_CPPFLAGS+=-I${R}/lib
LOCAL_LDFLAGS+=
LOCAL_LDADD+=-lcrypto ${LIB_ARGON2} ${LIBMOSQ_COMMON}
LOCAL_LDADD+=-lcrypto ${LIBMOSQ_COMMON}
.PHONY: all install uninstall clean reallyclean
@@ -12,8 +12,7 @@ OBJS= \
mosquitto_passwd.o \
get_password.o \
OBJS_EXTERNAL= \
password_mosq.o
OBJS_EXTERNAL=
ifeq ($(WITH_TLS),yes)
@@ -35,9 +34,6 @@ mosquitto_passwd.a : ${OBJS} ${OBJS_EXTERNAL}
${OBJS} : %.o: %.c
${CROSS_COMPILE}${CC} $(LOCAL_CPPFLAGS) $(LOCAL_CFLAGS) -c $< -o $@
password_mosq.o : ${R}/common/password_mosq.c ${R}/common/password_mosq.h
${CROSS_COMPILE}${CC} ${LOCAL_CPPFLAGS} $(LOCAL_CFLAGS) -c $< -o $@
install : all
ifeq ($(WITH_TLS),yes)
$(INSTALL) -d "${DESTDIR}$(prefix)/bin"
+18 -22
View File
@@ -29,7 +29,6 @@ Contributors:
#include "mosquitto.h"
#include "get_password.h"
#include "password_mosq.h"
#ifdef WIN32
# include <windows.h>
@@ -63,7 +62,7 @@ struct cb_helper {
bool found;
};
static enum mosquitto_pwhash_type hashtype = pw_argon2id;
static enum mosquitto_pwhash_type hashtype = MOSQ_PW_ARGON2ID;
#ifdef WIN32
static FILE *mpw_tmpfile(void)
@@ -123,33 +122,30 @@ static void print_usage(void)
static int output_new_password(FILE *fptr, const char *username, const char *password, int iterations)
{
int rc;
struct mosquitto_pw pw;
struct mosquitto_pw *pw;
if(password == NULL){
fprintf(stderr, "Error: Internal error, no password given.\n");
return 1;
}
memset(&pw, 0, sizeof(pw));
pw.hashtype = hashtype;
if(hashtype == pw_sha512_pbkdf2){
pw.params.sha512_pbkdf2.iterations = iterations;
if(mosquitto_pw_new(&pw, hashtype)){
fprintf(stderr, "Error: Out of memory.\n");
return 1;
}
rc = pw__create(&pw, password);
if(hashtype == MOSQ_PW_SHA512_PBKDF2 && iterations > 0){
mosquitto_pw_set_param(pw, MOSQ_PW_PARAM_ITERATIONS, iterations);
}
rc = mosquitto_pw_hash_encoded(pw, password);
if(rc){
mosquitto_pw_cleanup(pw);
fprintf(stderr, "Error: Unable to hash password.\n");
return rc;
}
rc = pw__encode(&pw);
if(rc){
fprintf(stderr, "Error: Unable to encode password.\n");
return rc;
}
fprintf(fptr, "%s:%s\n", username, pw.encoded_password);
mosquitto_FREE(pw.encoded_password);
fprintf(fptr, "%s:%s\n", username, mosquitto_pw_get_encoded(pw));
mosquitto_pw_cleanup(pw);
return rc;
}
@@ -269,7 +265,7 @@ static int update_file_cb(FILE *fptr, FILE *ftmp, const char *username, const ch
if(helper){
return output_new_password(ftmp, username, password, helper->iterations);
}else{
return output_new_password(ftmp, username, password, PW_DEFAULT_ITERATIONS);
return output_new_password(ftmp, username, password, -1);
}
}
@@ -431,7 +427,7 @@ int main(int argc, char *argv[])
bool do_update_file = false;
char *backup_file;
int idx;
int iterations = PW_DEFAULT_ITERATIONS;
int iterations = -1;
signal(SIGINT, handle_sigint);
signal(SIGTERM, handle_sigint);
@@ -457,11 +453,11 @@ int main(int argc, char *argv[])
return 1;
}
if(!strcmp(argv[idx+1], "argon2id")){
hashtype = pw_argon2id;
hashtype = MOSQ_PW_ARGON2ID;
}else if(!strcmp(argv[idx+1], "sha512-pbkdf2")){
hashtype = pw_sha512_pbkdf2;
hashtype = MOSQ_PW_SHA512_PBKDF2;
}else if(!strcmp(argv[idx+1], "sha512")){
hashtype = pw_sha512;
hashtype = MOSQ_PW_SHA512;
}else{
fprintf(stderr, "Error: Unknown hash type '%s'\n", argv[idx+1]);
return 1;
-70
View File
@@ -1,70 +0,0 @@
#ifndef PASSWORD_MOSQ_H
#define PASSWORD_MOSQ_H
/*
Copyright (c) 2012-2021 Roger Light <roger@atchoo.org>
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License 2.0
and Eclipse Distribution License v1.0 which accompany this distribution.
The Eclipse Public License is available at
https://www.eclipse.org/legal/epl-2.0/
and the Eclipse Distribution License is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Contributors:
Roger Light - initial implementation and documentation.
*/
#include <stdbool.h>
#ifdef WITH_TLS
# include <openssl/evp.h>
# define HASH_LEN EVP_MAX_MD_SIZE
#else
/* 64 bytes big enough for SHA512 */
# define HASH_LEN 64
#endif
enum mosquitto_pwhash_type{
pw_sha512 = 6,
pw_sha512_pbkdf2 = 7,
pw_argon2id = 8,
};
#define PW_DEFAULT_ITERATIONS 210000
struct mosquitto_pw{
union {
struct {
unsigned char password_hash[HASH_LEN]; /* For SHA512 */
unsigned char salt[HASH_LEN];
size_t salt_len;
} sha512;
struct {
unsigned char password_hash[HASH_LEN]; /* For SHA512 */
unsigned char salt[HASH_LEN];
size_t salt_len;
int iterations;
} sha512_pbkdf2;
struct {
unsigned char password_hash[HASH_LEN];
unsigned char salt[HASH_LEN];
size_t salt_len;
int iterations;
} argon2id;
} params;
char *encoded_password;
enum mosquitto_pwhash_type hashtype;
bool valid;
};
int pw__create(struct mosquitto_pw *pw, const char *password);
int pw__encode(struct mosquitto_pw *pw);
int pw__decode(struct mosquitto_pw *pw, const char *password);
int pw__verify(struct mosquitto_pw *pw, const char *password);
void pw__cleanup(struct mosquitto_pw *pw);
#endif
+1
View File
@@ -298,4 +298,5 @@ endif
ifeq ($(WITH_ARGON2),yes)
LOCAL_CPPFLAGS+=-DWITH_ARGON2
LIB_ARGON2=-largon2
LIBMOSQ_COMMON+=${LIB_ARGON2}
endif
+1 -1
View File
@@ -11,7 +11,7 @@ FUZZERS:= \
LOCAL_CPPFLAGS+=
LOCAL_CXXFLAGS+=-g -Wall -Werror -pthread
LOCAL_LDFLAGS+=
LOCAL_LIBADD+=$(LIB_FUZZING_ENGINE) ${R}/apps/db_dump/mosquitto_db_dump.a ${R}/libcommon/libmosquitto_common.a
LOCAL_LIBADD+=$(LIB_FUZZING_ENGINE) ${R}/apps/db_dump/mosquitto_db_dump.a ${R}/libcommon/libmosquitto_common.a -Wl,-Bstatic -largon2 -Wl,-Bdynamic
all: $(FUZZERS)
+1 -1
View File
@@ -9,7 +9,7 @@ FUZZERS:= \
LOCAL_CPPFLAGS+=
LOCAL_CXXFLAGS+=-g -Wall -Werror -pthread
LOCAL_LDFLAGS+=
LOCAL_LIBADD+=$(LIB_FUZZING_ENGINE) ${R}/apps/mosquitto_passwd/mosquitto_passwd.a -lssl -lcrypto -Wl,-Bstatic -largon2 -Wl,-Bdynamic ${R}/libcommon/libmosquitto_common.a
LOCAL_LIBADD+=$(LIB_FUZZING_ENGINE) ${R}/apps/mosquitto_passwd/mosquitto_passwd.a -lssl -lcrypto ${R}/libcommon/libmosquitto_common.a -Wl,-Bstatic -largon2 -Wl,-Bdynamic
all: $(FUZZERS)
+1 -1
View File
@@ -17,7 +17,7 @@ LOCAL_CPPFLAGS+=-I${R}/include/ -I${R}/src -I${R}/lib -I${R} -I${R}/common -I${R
-DWITH_SYS_TREE -DWITH_TLS -DWITH_TLS_PSK -DWITH_UNIX_SOCKETS -DWITH_WEBSOCKETS=WS_IS_BUILTIN
LOCAL_CXXFLAGS+=-g -Wall -Werror -pthread
LOCAL_LDFLAGS+=
LOCAL_LIBADD+=$(LIB_FUZZING_ENGINE) ${R}/src/mosquitto_broker.a -lssl -lcrypto -lcjson -Wl,-Bstatic -largon2 -Wl,-Bdynamic -lm ${R}/libcommon/libmosquitto_common.a
LOCAL_LIBADD+=$(LIB_FUZZING_ENGINE) ${R}/src/mosquitto_broker.a -lssl -lcrypto -lcjson -lm ${R}/libcommon/libmosquitto_common.a -Wl,-Bdynamic -Wl,-Bstatic -largon2 -Wl,-Bdynamic
all: $(FUZZERS)
+1 -1
View File
@@ -11,7 +11,7 @@ FUZZERS:= \
LOCAL_CPPFLAGS+=-I${R}/include/
LOCAL_CXXFLAGS+=-g -Wall -Werror -pthread
LOCAL_LDFLAGS+=
LOCAL_LIBADD+=$(LIB_FUZZING_ENGINE) ${R}/lib/libmosquitto.a -lssl -lcrypto ${R}/libcommon/libmosquitto_common.a
LOCAL_LIBADD+=$(LIB_FUZZING_ENGINE) ${R}/lib/libmosquitto.a -lssl -lcrypto ${R}/libcommon/libmosquitto_common.a -Wl,-Bstatic -largon2 -Wl,-Bdynamic
all: $(FUZZERS)
+1 -1
View File
@@ -18,7 +18,7 @@ LOCAL_LIBADD+=$(LIB_FUZZING_ENGINE) \
${R}/src/mosquitto_broker.a \
${R}/libcommon/libmosquitto_common.a \
-lssl -lcrypto -lcjson -lm \
-Wl,-Bstatic -largon2 -Wl,-Bdynamic
-Wl,-Bdynamic -Wl,-Bstatic -largon2 -Wl,-Bdynamic
all: $(FUZZERS)
+1
View File
@@ -39,6 +39,7 @@ extern "C" {
#include <mosquitto/libcommon_base64.h>
#include <mosquitto/libcommon_file.h>
#include <mosquitto/libcommon_memory.h>
#include <mosquitto/libcommon_password.h>
#include <mosquitto/libcommon_properties.h>
#include <mosquitto/libcommon_random.h>
#include <mosquitto/libcommon_string.h>
+58
View File
@@ -0,0 +1,58 @@
/*
Copyright (c) 2010-2021 Roger Light <roger@atchoo.org>
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License 2.0
and Eclipse Distribution License v1.0 which accompany this distribution.
The Eclipse Public License is available at
https://www.eclipse.org/legal/epl-2.0/
and the Eclipse Distribution License is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Contributors:
Roger Light - initial implementation and documentation.
*/
#ifndef MOSQUITTO_LIBCOMMON_PASSWORD_H
#define MOSQUITTO_LIBCOMMON_PASSWORD_H
/*
* File: mosquitto/libcommon_password.h
*/
#ifdef __cplusplus
extern "C" {
#endif
enum mosquitto_pwhash_type{
MOSQ_PW_DEFAULT,
MOSQ_PW_SHA512 = 6,
MOSQ_PW_SHA512_PBKDF2 = 7,
MOSQ_PW_ARGON2ID = 8,
};
enum mosquitto_pw_params{
MOSQ_PW_PARAM_ITERATIONS = 1,
};
struct mosquitto_pw;
libmosqcommon_EXPORT void mosquitto_pw_set_valid(struct mosquitto_pw *pw, bool valid);
libmosqcommon_EXPORT bool mosquitto_pw_is_valid(struct mosquitto_pw *pw);
libmosqcommon_EXPORT int mosquitto_pw_new(struct mosquitto_pw **pw, enum mosquitto_pwhash_type hashtype);
libmosqcommon_EXPORT void mosquitto_pw_cleanup(struct mosquitto_pw *pw);
libmosqcommon_EXPORT int mosquitto_pw_hash_encoded(struct mosquitto_pw *pw, const char *password);
libmosqcommon_EXPORT const char *mosquitto_pw_get_encoded(struct mosquitto_pw *pw);
libmosqcommon_EXPORT int mosquitto_pw_verify(struct mosquitto_pw *pw, const char *password);
libmosqcommon_EXPORT int mosquitto_pw_set_param(struct mosquitto_pw *pw, int param, int value);
libmosqcommon_EXPORT int mosquitto_pw_decode(struct mosquitto_pw *pw, const char *encoded_password);
#ifdef __cplusplus
}
#endif
#endif
+1 -1
View File
@@ -4,7 +4,7 @@ include ${R}/config.mk
LOCAL_CFLAGS+=-fPIC
LOCAL_CPPFLAGS+=-I${R}/libcommon
LOCAL_LDFLAGS+=-Wl,--version-script=linker.version -Wl,-soname,libmosquitto.so.$(SOVERSION) -fPIC -shared
LOCAL_LIBADD+=-lcjson -lc ${LIB_ARGON2} ${LIBMOSQ_COMMON}
LOCAL_LIBADD+=-lcjson -lc ${LIBMOSQ_COMMON}
STATIC_LIB_DEPS:=
# ------------------------------------------
+5
View File
@@ -3,6 +3,7 @@ set(C_SRC
file_common.c
memory_common.c
mqtt_common.c
password_common.c
property_common.c
random_common.c
strings_common.c
@@ -43,6 +44,10 @@ target_link_libraries(libmosquitto_common
config-header
)
if(ARGON2_FOUND)
target_link_libraries(libmosquitto_common PRIVATE argon2)
endif()
if (WITH_TLS)
target_link_libraries(libmosquitto_common
PUBLIC
+1
View File
@@ -28,6 +28,7 @@ OBJS= \
file_common.o \
memory_common.o \
mqtt_common.o \
password_common.o \
property_common.o \
random_common.o \
strings_common.o \
@@ -18,33 +18,23 @@ Contributors:
#include "config.h"
#include <stdbool.h>
#include <string.h>
#ifdef WITH_TLS
# include <openssl/opensslv.h>
# include <openssl/evp.h>
# include <openssl/rand.h>
# define HASH_LEN EVP_MAX_MD_SIZE
#endif
#include <string.h>
#include "mosquitto.h"
#include "password_mosq.h"
#ifdef WIN32
# include <windows.h>
# include <process.h>
# ifndef __cplusplus
# if defined(_MSC_VER) && _MSC_VER < 1900
# define bool char
# define true 1
# define false 0
# else
# include <stdbool.h>
# endif
# endif
# define snprintf sprintf_s
# include <io.h>
# include <windows.h>
#ifdef WITH_TLS
# define HASH_LEN EVP_MAX_MD_SIZE
#else
# include <stdbool.h>
/* 64 bytes big enough for SHA512 */
# define HASH_LEN 64
#endif
#ifdef WITH_ARGON2
@@ -54,7 +44,35 @@ Contributors:
# define MOSQ_ARGON2_P 1
#endif
int pw__memcmp_const(const void *a, const void *b, size_t len)
#define PW_DEFAULT_ITERATIONS 210000
static int pw__encode(struct mosquitto_pw *pw);
struct mosquitto_pw{
union {
struct {
unsigned char password_hash[HASH_LEN]; /* For SHA512 */
unsigned char salt[HASH_LEN];
size_t salt_len;
} sha512;
struct {
unsigned char password_hash[HASH_LEN]; /* For SHA512 */
unsigned char salt[HASH_LEN];
size_t salt_len;
int iterations;
} sha512_pbkdf2;
struct {
unsigned char password_hash[HASH_LEN];
unsigned char salt[HASH_LEN];
size_t salt_len;
int iterations;
} argon2id;
} params;
char *encoded_password;
enum mosquitto_pwhash_type hashtype;
bool valid;
};
static int pw__memcmp_const(const void *a, const void *b, size_t len)
{
#ifdef WITH_TLS
return CRYPTO_memcmp(a, b, len);
@@ -79,7 +97,7 @@ int pw__memcmp_const(const void *a, const void *b, size_t len)
static int pw__create_argon2id(struct mosquitto_pw *pw, const char *password)
{
#ifdef WITH_ARGON2
pw->hashtype = pw_argon2id;
pw->hashtype = MOSQ_PW_ARGON2ID;
pw->params.argon2id.salt_len = HASH_LEN;
int rc = RAND_bytes(pw->params.argon2id.salt, (int)pw->params.argon2id.salt_len);
if(!rc){
@@ -99,6 +117,7 @@ static int pw__create_argon2id(struct mosquitto_pw *pw, const char *password)
pw->encoded_password, encoded_len+1);
if(rc == ARGON2_OK){
pw->valid = true;
return MOSQ_ERR_SUCCESS;
}else{
return MOSQ_ERR_UNKNOWN;
@@ -136,6 +155,7 @@ static int pw__decode_argon2id(struct mosquitto_pw *pw, const char *password)
if(new_password){
mosquitto_free(pw->encoded_password);
pw->encoded_password = new_password;
pw->valid = true;
return MOSQ_ERR_SUCCESS;
}else{
return MOSQ_ERR_NOMEM;
@@ -172,7 +192,7 @@ static int pw__hash_sha512_pbkdf2(const char *password, struct mosquitto_pw *pw,
static int pw__create_sha512_pbkdf2(struct mosquitto_pw *pw, const char *password)
{
#ifdef WITH_TLS
pw->hashtype = pw_sha512_pbkdf2;
pw->hashtype = MOSQ_PW_SHA512_PBKDF2;
pw->params.sha512_pbkdf2.salt_len = HASH_LEN;
int rc = RAND_bytes(pw->params.sha512_pbkdf2.salt, (int)pw->params.sha512_pbkdf2.salt_len);
if(!rc){
@@ -182,10 +202,13 @@ static int pw__create_sha512_pbkdf2(struct mosquitto_pw *pw, const char *passwor
if(pw->params.sha512_pbkdf2.iterations == 0){
pw->params.sha512_pbkdf2.iterations = PW_DEFAULT_ITERATIONS;
}
return pw__hash_sha512_pbkdf2(password, pw,
rc = pw__hash_sha512_pbkdf2(password, pw,
pw->params.sha512_pbkdf2.password_hash,
sizeof(pw->params.sha512_pbkdf2.password_hash),
pw->params.sha512_pbkdf2.iterations);
pw->valid = (rc == MOSQ_ERR_SUCCESS);
return rc;
#else
return MOSQ_ERR_NOT_SUPPORTED;
#endif
@@ -303,6 +326,7 @@ static int pw__decode_sha512_pbkdf2(struct mosquitto_pw *pw, const char *salt_pa
memcpy(pw->params.sha512_pbkdf2.password_hash, password, password_len);
mosquitto_free(password);
pw->valid = true;
return MOSQ_ERR_SUCCESS;
#else
return MOSQ_ERR_NOT_SUPPORTED;
@@ -351,14 +375,16 @@ static int pw__hash_sha512(const char *password, struct mosquitto_pw *pw, unsign
static int pw__create_sha512(struct mosquitto_pw *pw, const char *password)
{
#ifdef WITH_TLS
pw->hashtype = pw_sha512;
pw->hashtype = MOSQ_PW_SHA512;
pw->params.sha512.salt_len = HASH_LEN;
int rc = RAND_bytes(pw->params.sha512.salt, (int)pw->params.sha512.salt_len);
if(!rc){
return MOSQ_ERR_UNKNOWN;
}
return pw__hash_sha512(password, pw, pw->params.sha512.password_hash, sizeof(pw->params.sha512.password_hash));
rc = pw__hash_sha512(password, pw, pw->params.sha512.password_hash, sizeof(pw->params.sha512.password_hash));
pw->valid = (rc == MOSQ_ERR_SUCCESS);
return rc;
#else
return MOSQ_ERR_NOT_SUPPORTED;
#endif
@@ -460,88 +486,153 @@ static int pw__decode_sha512(struct mosquitto_pw *pw, const char *salt_password)
memcpy(pw->params.sha512.password_hash, password, password_len);
mosquitto_free(password);
pw->valid = true;
return MOSQ_ERR_SUCCESS;
#else
return MOSQ_ERR_NOT_SUPPORTED;
#endif
}
static int pw__encode(struct mosquitto_pw *pw)
{
switch(pw->hashtype){
case MOSQ_PW_ARGON2ID:
return MOSQ_ERR_SUCCESS;
case MOSQ_PW_SHA512_PBKDF2:
return pw__encode_sha512_pbkdf2(pw);
case MOSQ_PW_SHA512:
return pw__encode_sha512(pw);
case MOSQ_PW_DEFAULT:
break;
}
return MOSQ_ERR_AUTH;
}
/* ==================================================
* Public
* ================================================== */
int pw__create(struct mosquitto_pw *pw, const char *password)
int mosquitto_pw_new(struct mosquitto_pw **pw, enum mosquitto_pwhash_type hashtype)
{
*pw = mosquitto_calloc(1, sizeof(struct mosquitto_pw));
if(*pw){
(*pw)->hashtype = hashtype;
return MOSQ_ERR_SUCCESS;
}else{
return MOSQ_ERR_NOMEM;
}
}
int mosquitto_pw_hash_encoded(struct mosquitto_pw *pw, const char *password)
{
int rc = MOSQ_ERR_INVAL;
switch(pw->hashtype){
case pw_argon2id:
return pw__create_argon2id(pw, password);
case pw_sha512_pbkdf2:
return pw__create_sha512_pbkdf2(pw, password);
case pw_sha512:
return pw__create_sha512(pw, password);
case MOSQ_PW_DEFAULT:
case MOSQ_PW_ARGON2ID:
rc = pw__create_argon2id(pw, password);
case MOSQ_PW_SHA512_PBKDF2:
rc = pw__create_sha512_pbkdf2(pw, password);
case MOSQ_PW_SHA512:
rc = pw__create_sha512(pw, password);
default:
#ifdef WITH_ARGON2
return pw__create_argon2id(pw, password);
rc = pw__create_argon2id(pw, password);
#else
return pw__create_sha512_pbkdf2(pw, password);
rc = pw__create_sha512_pbkdf2(pw, password);
#endif
}
return MOSQ_ERR_INVAL;
if(rc == MOSQ_ERR_SUCCESS){
return pw__encode(pw);
}else{
return rc;
}
}
int pw__verify(struct mosquitto_pw *pw, const char *password)
int mosquitto_pw_verify(struct mosquitto_pw *pw, const char *password)
{
switch(pw->hashtype){
case pw_argon2id:
return pw__verify_argon2id(pw, password);
case pw_sha512_pbkdf2:
return pw__verify_sha512_pbkdf2(pw, password);
case pw_sha512:
return pw__verify_sha512(pw, password);
if(pw && pw->valid){
switch(pw->hashtype){
case MOSQ_PW_ARGON2ID:
return pw__verify_argon2id(pw, password);
case MOSQ_PW_SHA512_PBKDF2:
return pw__verify_sha512_pbkdf2(pw, password);
case MOSQ_PW_SHA512:
return pw__verify_sha512(pw, password);
case MOSQ_PW_DEFAULT:
return MOSQ_ERR_AUTH;
}
}
return MOSQ_ERR_AUTH;
}
int pw__encode(struct mosquitto_pw *pw)
void mosquitto_pw_set_valid(struct mosquitto_pw *pw, bool valid)
{
switch(pw->hashtype){
case pw_argon2id:
return MOSQ_ERR_SUCCESS;
case pw_sha512_pbkdf2:
return pw__encode_sha512_pbkdf2(pw);
case pw_sha512:
return pw__encode_sha512(pw);
if(pw){
pw->valid = valid;
}
return MOSQ_ERR_AUTH;
}
int pw__decode(struct mosquitto_pw *pw, const char *password)
bool mosquitto_pw_is_valid(struct mosquitto_pw *pw)
{
return pw && pw->valid;
}
int mosquitto_pw_decode(struct mosquitto_pw *pw, const char *password)
{
if(!pw) return MOSQ_ERR_INVAL;
pw->valid = false;
if(password[0] != '$'){
return MOSQ_ERR_INVAL;
}
pw->encoded_password = mosquitto_strdup(password);
if(!pw->encoded_password){
return MOSQ_ERR_NOMEM;
}
if(password[1] == '6' && password[2] == '$'){
pw->hashtype = pw_sha512;
pw->hashtype = MOSQ_PW_SHA512;
return pw__decode_sha512(pw, &password[3]);
}else if(password[1] == '7' && password[2] == '$'){
pw->hashtype = pw_sha512_pbkdf2;
pw->hashtype = MOSQ_PW_SHA512_PBKDF2;
return pw__decode_sha512_pbkdf2(pw, &password[3]);
}else if(!strncmp(password, "$argon2id$", strlen("$argon2id$"))){
pw->hashtype = pw_argon2id;
pw->hashtype = MOSQ_PW_ARGON2ID;
return pw__decode_argon2id(pw, password);
}else{
mosquitto_FREE(pw->encoded_password);
return MOSQ_ERR_INVAL;
}
}
void pw__cleanup(struct mosquitto_pw *pw)
const char *mosquitto_pw_get_encoded(struct mosquitto_pw *pw)
{
return pw?pw->encoded_password:NULL;
}
int mosquitto_pw_set_param(struct mosquitto_pw *pw, int param, int value)
{
if(!pw) return MOSQ_ERR_INVAL;
switch(param){
case MOSQ_PW_PARAM_ITERATIONS:
if(pw->hashtype != MOSQ_PW_SHA512_PBKDF2) return MOSQ_ERR_INVAL;
pw->params.sha512_pbkdf2.iterations = value;
break;
}
return MOSQ_ERR_SUCCESS;
}
void mosquitto_pw_cleanup(struct mosquitto_pw *pw)
{
if(pw){
mosquitto_free(pw->encoded_password);
pw->encoded_password = NULL;
mosquitto_free(pw);
}
}
-1
View File
@@ -15,7 +15,6 @@ if(WITH_TLS)
grouplist.c
../../common/json_help.c ../../common/json_help.h
kicklist.c
../../common/password_mosq.c ../../common/password_mosq.h
plugin.c
roles.c
rolelist.c
+1 -5
View File
@@ -31,8 +31,7 @@ OBJS = \
tick.o
OBJS_EXTERNAL = \
json_help.o \
password_mosq.o \
json_help.o
EXTRA_DEPS:=dynamic_security.h
@@ -47,7 +46,4 @@ all : ${ALL_DEPS}
json_help.o : ${R}/common/json_help.c ${R}/common/json_help.h
${CROSS_COMPILE}${CC} $(LOCAL_CPPFLAGS) $(LOCAL_CFLAGS) -c $< -o $@
password_mosq.o : ${R}/common/password_mosq.c ${R}/common/password_mosq.h
${CROSS_COMPILE}${CC} $(LOCAL_CPPFLAGS) $(LOCAL_CFLAGS) -c $< -o $@
include ${R}/plugins/plugin.mk
+1 -2
View File
@@ -25,7 +25,6 @@ Contributors:
#include "dynamic_security.h"
/* ################################################################
* #
* # Username/password check
@@ -55,7 +54,7 @@ int dynsec_auth__basic_auth_callback(int event, void *event_data, void *userdata
return MOSQ_ERR_AUTH;
}
}
if(client->pw.valid && pw__verify(&client->pw, ed->password) == MOSQ_ERR_SUCCESS){
if(mosquitto_pw_verify(client->pw, ed->password) == MOSQ_ERR_SUCCESS){
return MOSQ_ERR_SUCCESS;
}else{
return MOSQ_ERR_AUTH;
+24 -68
View File
@@ -81,6 +81,7 @@ static void client__free_item(struct dynsec__data *data, struct dynsec__client *
}
dynsec_rolelist__cleanup(&client->rolelist);
dynsec__remove_client_from_all_groups(data, client->username);
mosquitto_pw_cleanup(client->pw);
mosquitto_free(client->text_name);
mosquitto_free(client->text_description);
mosquitto_free(client->clientid);
@@ -107,8 +108,6 @@ int dynsec_clients__config_load(struct dynsec__data *data, cJSON *tree)
cJSON *j_clients, *j_client = NULL, *j_roles, *j_role;
struct dynsec__client *client;
struct dynsec__role *role;
unsigned char *buf;
unsigned int buf_len;
int priority;
j_clients = cJSON_GetObjectItem(tree, "clients");
@@ -147,10 +146,11 @@ int dynsec_clients__config_load(struct dynsec__data *data, cJSON *tree)
const char *password;
if(json_get_string(j_client, "encoded_password", &password, false) == MOSQ_ERR_SUCCESS){
if(pw__decode(&client->pw, password) == MOSQ_ERR_SUCCESS){
client->pw.valid = true;
}else{
client->pw.valid = false;
if(!client->pw && mosquitto_pw_new(&client->pw, MOSQ_PW_DEFAULT)){
return MOSQ_ERR_NOMEM;
}
if(mosquitto_pw_decode(client->pw, password) == MOSQ_ERR_NOMEM){
return MOSQ_ERR_NOMEM;
}
}else{
/* sha512-pbkdf2 only */
@@ -161,32 +161,14 @@ int dynsec_clients__config_load(struct dynsec__data *data, cJSON *tree)
&& json_get_string(j_client, "password", &password, false) == MOSQ_ERR_SUCCESS
&& iterations > 0){
client->pw.hashtype = pw_sha512_pbkdf2;
client->pw.params.sha512_pbkdf2.iterations = iterations;
if(mosquitto_base64_decode(salt, &buf, &buf_len) != MOSQ_ERR_SUCCESS
|| buf_len > sizeof(client->pw.params.sha512_pbkdf2.salt)){
mosquitto_free(buf);
mosquitto_free(client);
continue;
char buf[1024];
if(!client->pw && mosquitto_pw_new(&client->pw, MOSQ_PW_SHA512_PBKDF2)){
return MOSQ_ERR_NOMEM;
}
memcpy(client->pw.params.sha512_pbkdf2.salt, buf, (size_t)buf_len);
client->pw.params.sha512_pbkdf2.salt_len = (size_t)buf_len;
mosquitto_free(buf);
if(mosquitto_base64_decode(password, &buf, &buf_len) != MOSQ_ERR_SUCCESS
|| buf_len != sizeof(client->pw.params.sha512_pbkdf2.password_hash)){
mosquitto_free(buf);
mosquitto_free(client);
continue;
}
memcpy(client->pw.params.sha512_pbkdf2.password_hash, buf, (size_t)buf_len);
mosquitto_free(buf);
client->pw.valid = true;
snprintf(buf, sizeof(buf), "$7$%d$%s$%s", iterations, salt, password);
mosquitto_pw_decode(client->pw, buf);
}else{
client->pw.valid = false;
mosquitto_pw_set_valid(client->pw, false);
}
}
@@ -275,34 +257,9 @@ static int dynsec__config_add_clients(struct dynsec__data *data, cJSON *j_client
}
cJSON_AddItemToObject(j_client, "roles", j_roles);
if(client->pw.valid){
if(client->pw.hashtype == pw_sha512_pbkdf2){
char *buf;
if(mosquitto_base64_encode(client->pw.params.sha512_pbkdf2.password_hash, sizeof(client->pw.params.sha512_pbkdf2.password_hash), &buf) != MOSQ_ERR_SUCCESS){
return 1;
}
cJSON *jtmp = cJSON_CreateString(buf);
mosquitto_free(buf);
if(jtmp == NULL) return 1;
cJSON_AddItemToObject(j_client, "password", jtmp);
if(mosquitto_base64_encode(client->pw.params.sha512_pbkdf2.salt, client->pw.params.sha512_pbkdf2.salt_len, &buf) != MOSQ_ERR_SUCCESS){
return 1;
}
jtmp = cJSON_CreateString(buf);
mosquitto_free(buf);
if(jtmp == NULL) return 1;
cJSON_AddItemToObject(j_client, "salt", jtmp);
if(cJSON_AddIntToObject(j_client, "iterations", client->pw.params.sha512_pbkdf2.iterations) == NULL){
return 1;
}
}else{
if(cJSON_AddStringToObject(j_client, "encoded_password", client->pw.encoded_password) == NULL){
return 1;
}
if(mosquitto_pw_is_valid(client->pw)){
if(cJSON_AddStringToObject(j_client, "encoded_password", mosquitto_pw_get_encoded(client->pw)) == NULL){
return 1;
}
}
}
@@ -407,12 +364,14 @@ int dynsec_clients__process_create(struct dynsec__data *data, struct mosquitto_c
}
if(password){
if(pw__create(&client->pw, password)){
if(mosquitto_pw_new(&client->pw, MOSQ_PW_DEFAULT)
|| mosquitto_pw_hash_encoded(client->pw, password)
){
mosquitto_control_command_reply(cmd, "Internal error");
client__free_item(data, client);
return MOSQ_ERR_NOMEM;
}
client->pw.valid = true;
}
if(clientid && strlen(clientid) > 0){
client->clientid = mosquitto_strdup(clientid);
@@ -649,15 +608,12 @@ int dynsec_clients__process_set_id(struct dynsec__data *data, struct mosquitto_c
static int client__set_password(struct dynsec__client *client, const char *password)
{
if(pw__create(&client->pw, password) == MOSQ_ERR_SUCCESS){
client->pw.valid = true;
return MOSQ_ERR_SUCCESS;
}else{
client->pw.valid = false;
/* FIXME - this should fail safe without modifying the existing password */
return MOSQ_ERR_NOMEM;
if(!client->pw){
if(mosquitto_pw_new(&client->pw, MOSQ_PW_DEFAULT)){
return MOSQ_ERR_NOMEM;
}
}
return mosquitto_pw_hash_encoded(client->pw, password);
}
int dynsec_clients__process_set_password(struct dynsec__data *data, struct mosquitto_control_cmd *cmd)
+7 -36
View File
@@ -109,15 +109,13 @@ static int get_password_from_init_file(struct dynsec__data *data, char **pw)
*/
static int generate_password(struct dynsec__data *data, cJSON *j_client, char **password)
{
struct mosquitto_pw pw;
struct mosquitto_pw *pw;
int i;
unsigned char vb;
unsigned long v;
size_t len;
char *pwenv;
memset(&pw, 0, sizeof(struct mosquitto_pw));
if(data->init_mode == dpwim_file){
if(get_password_from_init_file(data, password)){
return MOSQ_ERR_INVAL;
@@ -151,44 +149,17 @@ static int generate_password(struct dynsec__data *data, cJSON *j_client, char **
(*password)[20] = '\0';
}
if(pw__create(&pw, *password) != MOSQ_ERR_SUCCESS){
if(mosquitto_pw_new(&pw, MOSQ_PW_DEFAULT) != MOSQ_ERR_SUCCESS
|| mosquitto_pw_hash_encoded(pw, *password) != MOSQ_ERR_SUCCESS
|| cJSON_AddStringToObject(j_client, "encoded_password", mosquitto_pw_get_encoded(pw)) == NULL){
mosquitto_pw_cleanup(pw);
free(*password);
*password = NULL;
return MOSQ_ERR_UNKNOWN;
}
if(pw.hashtype == pw_sha512_pbkdf2){
char *salt_b64 = NULL, *password_b64 = NULL;
if(mosquitto_base64_encode(pw.params.sha512_pbkdf2.salt, pw.params.sha512_pbkdf2.salt_len, &salt_b64)
|| mosquitto_base64_encode(pw.params.sha512_pbkdf2.password_hash, sizeof(pw.params.sha512_pbkdf2.password_hash), &password_b64)
|| cJSON_AddStringToObject(j_client, "salt", salt_b64) == NULL
|| cJSON_AddStringToObject(j_client, "password", password_b64) == NULL
|| cJSON_AddNumberToObject(j_client, "iterations", pw.params.sha512_pbkdf2.iterations) == NULL){
free(password_b64);
free(salt_b64);
free(*password);
*password = NULL;
return MOSQ_ERR_UNKNOWN;
}
free(password_b64);
free(salt_b64);
}else{
if(pw__encode(&pw) != MOSQ_ERR_SUCCESS){
free(*password);
*password = NULL;
return MOSQ_ERR_UNKNOWN;
}
if(cJSON_AddStringToObject(j_client, "encoded_password", pw.encoded_password) == NULL){
free(pw.encoded_password);
free(*password);
*password = NULL;
return MOSQ_ERR_UNKNOWN;
}
free(pw.encoded_password);
}
mosquitto_pw_cleanup(pw);
return MOSQ_ERR_SUCCESS;
}
+1 -2
View File
@@ -21,7 +21,6 @@ Contributors:
#include <cjson/cJSON.h>
#include <uthash.h>
#include "mosquitto.h"
#include "password_mosq.h"
#define PRIORITY_MAX 100000
@@ -82,7 +81,7 @@ struct dynsec__kicklist{
struct dynsec__client{
UT_hash_handle hh;
struct mosquitto_pw pw;
struct mosquitto_pw *pw;
struct dynsec__rolelist *rolelist;
struct dynsec__grouplist *grouplist;
char *clientid;
+1 -5
View File
@@ -36,7 +36,6 @@ add_executable(mosquitto
../lib/net_ws.c
../lib/packet_datatypes.c
../lib/packet_mosq.c ../lib/packet_mosq.h
../common/password_mosq.c ../common/password_mosq.h
persist_read_v234.c persist_read_v5.c persist_read.c
persist_write_v5.c persist_write.c
persist.h
@@ -51,6 +50,7 @@ add_executable(mosquitto
property_broker.c
proxy_v2.c
../lib/property_mosq.c ../lib/property_mosq.h
psk_file.c
read_handle.c
../lib/read_handle.h
retain.c
@@ -136,10 +136,6 @@ if(WITH_CONTROL)
target_compile_definitions(mosquitto PRIVATE "WITH_CONTROL")
endif()
if(ARGON2_FOUND)
target_link_libraries(mosquitto PRIVATE argon2)
endif()
if(WIN32 OR CYGWIN)
target_sources(mosquitto PRIVATE service.c)
endif()
+2 -5
View File
@@ -6,7 +6,7 @@ include ${R}/config.mk
LOCAL_CFLAGS+=
LOCAL_CPPFLAGS+=-DWITH_BROKER -I${R}/lib -I${R}/libcommon
LOCAL_LDFLAGS+=
LOCAL_LDADD+=-lcjson -lm ${LIB_ARGON2} ${LIBMOSQ_COMMON}
LOCAL_LDADD+=-lcjson -lm ${LIBMOSQ_COMMON}
# ------------------------------------------
# Platform specific
@@ -94,6 +94,7 @@ OBJS= mosquitto.o \
plugin_unsubscribe.o \
plugin_tick.o \
proxy_v2.o \
psk_file.o \
read_handle.o \
retain.o \
security_default.o \
@@ -125,7 +126,6 @@ OBJS_EXTERNAL= \
net_ws.o \
packet_datatypes.o \
packet_mosq.o \
password_mosq.o \
property_mosq.o \
send_connect.o \
send_disconnect.o \
@@ -183,9 +183,6 @@ net_mosq.o : ${R}/lib/net_mosq.c ${R}/lib/net_mosq.h
net_ws.o : ${R}/lib/net_ws.c ${R}/lib/net_mosq.h
${CROSS_COMPILE}${CC} $(LOCAL_CPPFLAGS) $(LOCAL_CFLAGS) -c $< -o $@
password_mosq.o : ${R}/common/password_mosq.c ${R}/common/password_mosq.h mosquitto_broker_internal.h
${CROSS_COMPILE}${CC} $(LOCAL_CPPFLAGS) $(LOCAL_CFLAGS) -c $< -o $@
packet_datatypes.o : ${R}/lib/packet_datatypes.c ${R}/lib/packet_mosq.h
${CROSS_COMPILE}${CC} $(LOCAL_CPPFLAGS) $(LOCAL_CFLAGS) -c $< -o $@
+10 -3
View File
@@ -39,7 +39,6 @@ Contributors:
#include "mosquitto/broker_plugin.h"
#include "mosquitto.h"
#include "logging_mosq.h"
#include "password_mosq.h"
#include "tls_mosq.h"
#include "uthash.h"
@@ -194,7 +193,7 @@ struct mosquitto__security_options {
* should be disabled when these options are set.
*/
struct mosquitto__unpwd *unpwd;
struct mosquitto__unpwd *psk_id;
struct mosquitto__psk *psk_id;
struct mosquitto__acl_user *acl_list;
struct mosquitto__acl *acl_patterns;
char *password_file;
@@ -425,11 +424,17 @@ struct mosquitto__client_msg{
};
struct mosquitto__psk{
UT_hash_handle hh;
char *username;
char *password;
};
struct mosquitto__unpwd{
UT_hash_handle hh;
char *username;
char *clientid;
struct mosquitto_pw pw;
struct mosquitto_pw *pw;
};
struct mosquitto__acl{
@@ -910,6 +915,8 @@ int mosquitto_security_init_default(bool reload);
int mosquitto_security_apply_default(void);
int mosquitto_security_cleanup_default(bool reload);
int mosquitto_psk_key_get_default(struct mosquitto *context, const char *hint, const char *identity, char *key, int max_key_len);
int psk_file__init(void);
int psk_file__cleanup(void);
int mosquitto_security_auth_start(struct mosquitto *context, bool reauth, const void *data_in, uint16_t data_in_len, void **data_out, uint16_t *data_out_len);
int mosquitto_security_auth_continue(struct mosquitto *context, const void *data_in, uint16_t data_len, void **data_out, uint16_t *data_out_len);
+256
View File
@@ -0,0 +1,256 @@
/*
Copyright (c) 2011-2021 Roger Light <roger@atchoo.org>
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License 2.0
and Eclipse Distribution License v1.0 which accompany this distribution.
The Eclipse Public License is available at
https://www.eclipse.org/legal/epl-2.0/
and the Eclipse Distribution License is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Contributors:
Roger Light - initial implementation and documentation.
*/
#include "config.h"
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "mosquitto_broker_internal.h"
#include "mosquitto/mqtt_protocol.h"
#include "send_mosq.h"
#include "util_mosq.h"
static int psk__cleanup(struct mosquitto__psk **psk);
static int psk__file_parse(struct mosquitto__psk **psk_id, const char *psk_file);
int psk_file__init(void)
{
int rc;
char *pskf = NULL;
/* Load psk data if required. */
if(db.config->per_listener_settings){
for(int i=0; i<db.config->listener_count; i++){
pskf = db.config->listeners[i].security_options->psk_file;
if(pskf){
rc = psk__file_parse(&db.config->listeners[i].security_options->psk_id, pskf);
if(rc){
log__printf(NULL, MOSQ_LOG_ERR, "Error opening psk file \"%s\".", pskf);
return rc;
}
}
}
}else{
pskf = db.config->security_options.psk_file;
if(pskf){
rc = psk__file_parse(&db.config->security_options.psk_id, pskf);
if(rc){
log__printf(NULL, MOSQ_LOG_ERR, "Error opening psk file \"%s\".", pskf);
return rc;
}
}
}
return MOSQ_ERR_SUCCESS;
}
int psk_file__cleanup(void)
{
int rc;
rc = psk__cleanup(&db.config->security_options.psk_id);
if(rc != MOSQ_ERR_SUCCESS) return rc;
for(int i=0; i<db.config->listener_count; i++){
if(db.config->listeners[i].security_options->psk_id){
rc = psk__cleanup(&db.config->listeners[i].security_options->psk_id);
if(rc != MOSQ_ERR_SUCCESS) return rc;
}
}
return MOSQ_ERR_SUCCESS;
}
static int pwfile__parse(const char *file, struct mosquitto__psk **root)
{
FILE *pwfile;
struct mosquitto__psk *psk;
char *username, *password;
char *saveptr = NULL;
char *buf;
int buflen = 256;
buf = mosquitto_malloc((size_t)buflen);
if(buf == NULL){
log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
return MOSQ_ERR_NOMEM;
}
pwfile = mosquitto_fopen(file, "rt", true);
if(!pwfile){
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open pwfile \"%s\".", file);
mosquitto_FREE(buf);
return MOSQ_ERR_UNKNOWN;
}
while(!feof(pwfile)){
if(mosquitto_fgets(&buf, &buflen, pwfile)){
if(buf[0] == '#') continue;
if(!strchr(buf, ':')) continue;
username = strtok_r(buf, ":", &saveptr);
if(username){
username = mosquitto_trimblanks(username);
if(strlen(username) > 65535){
log__printf(NULL, MOSQ_LOG_NOTICE, "Warning: Invalid line in password file '%s', username too long.", file);
continue;
}
if(strlen(username) <= 0){
log__printf(NULL, MOSQ_LOG_NOTICE, "Warning: Empty username in password file '%s', ingoring.", file);
continue;
}
HASH_FIND(hh, *root, username, strlen(username), psk);
if(psk){
log__printf(NULL, MOSQ_LOG_NOTICE, "Error: Duplicate user '%s' in password file '%s', ignoring.", username, file);
continue;
}
psk = mosquitto_calloc(1, sizeof(struct mosquitto__psk));
if(!psk){
fclose(pwfile);
mosquitto_FREE(buf);
return MOSQ_ERR_NOMEM;
}
psk->username = mosquitto_strdup(username);
if(!psk->username){
mosquitto_FREE(psk);
mosquitto_FREE(buf);
fclose(pwfile);
return MOSQ_ERR_NOMEM;
}
password = strtok_r(NULL, ":", &saveptr);
if(password){
password = mosquitto_trimblanks(password);
if(strlen(password) > 65535){
log__printf(NULL, MOSQ_LOG_NOTICE, "Warning: Invalid line in password file '%s', password too long.", file);
mosquitto_FREE(psk->username);
mosquitto_FREE(psk);
continue;
}
psk->password = mosquitto_strdup(password);
if(!psk->password){
log__printf(NULL, MOSQ_LOG_NOTICE, "Warning: Unable to decode line in password file '%s'.", file);
mosquitto_FREE(psk->username);
mosquitto_FREE(psk);
continue;
}
HASH_ADD_KEYPTR(hh, *root, psk->username, strlen(psk->username), psk);
}else{
log__printf(NULL, MOSQ_LOG_NOTICE, "Warning: Invalid line in psk file '%s': %s", file, buf);
mosquitto_FREE(psk->username);
mosquitto_FREE(psk->password);
mosquitto_FREE(psk);
}
}
}
}
fclose(pwfile);
mosquitto_FREE(buf);
return MOSQ_ERR_SUCCESS;
}
void psk__free_item(struct mosquitto__psk **psk, struct mosquitto__psk *item)
{
mosquitto_FREE(item->username);
mosquitto_FREE(item->password);
HASH_DEL(*psk, item);
mosquitto_FREE(item);
}
static int psk__file_parse(struct mosquitto__psk **psk_id, const char *psk_file)
{
int rc;
struct mosquitto__psk *psk, *tmp = NULL;
if(!db.config || !psk_id) return MOSQ_ERR_INVAL;
/* We haven't been asked to parse a psk file. */
if(!psk_file) return MOSQ_ERR_SUCCESS;
rc = pwfile__parse(psk_file, psk_id);
if(rc) return rc;
HASH_ITER(hh, (*psk_id), psk, tmp){
/* Check for hex only digits */
if(!psk->password){
log__printf(NULL, MOSQ_LOG_ERR, "Error: Empty psk for identity \"%s\".", psk->username);
return MOSQ_ERR_INVAL;
}
if(strspn(psk->password, "0123456789abcdefABCDEF") < strlen(psk->password)){
log__printf(NULL, MOSQ_LOG_ERR, "Error: psk for identity \"%s\" contains non-hexadecimal characters.", psk->username);
return MOSQ_ERR_INVAL;
}
}
return MOSQ_ERR_SUCCESS;
}
static int psk__cleanup(struct mosquitto__psk **root)
{
struct mosquitto__psk *psk, *tmp = NULL;
if(!root) return MOSQ_ERR_INVAL;
HASH_ITER(hh, *root, psk, tmp){
HASH_DEL(*root, psk);
mosquitto_FREE(psk->username);
mosquitto_FREE(psk->password);
mosquitto_FREE(psk);
}
*root = NULL;
return MOSQ_ERR_SUCCESS;
}
int mosquitto_psk_key_get_default(struct mosquitto *context, const char *hint, const char *identity, char *key, int max_key_len)
{
struct mosquitto__psk *psk;
struct mosquitto__psk *psk_id_ref = NULL;
if(!hint || !identity || !key) return MOSQ_ERR_INVAL;
if(db.config->per_listener_settings){
if(!context->listener) return MOSQ_ERR_INVAL;
psk_id_ref = context->listener->security_options->psk_id;
}else{
psk_id_ref = db.config->security_options.psk_id;
}
if(!psk_id_ref) return MOSQ_ERR_PLUGIN_IGNORE;
HASH_FIND(hh, psk_id_ref, identity, strlen(identity), psk);
if(psk){
strncpy(key, psk->password, (size_t)max_key_len);
return MOSQ_ERR_SUCCESS;
}
return MOSQ_ERR_AUTH;
}
+14 -125
View File
@@ -31,7 +31,6 @@ static int aclfile__parse(struct mosquitto__security_options *security_opts);
static int unpwd__file_parse(struct mosquitto__unpwd **unpwd, const char *password_file);
static int acl__cleanup(bool reload);
static int unpwd__cleanup(struct mosquitto__unpwd **unpwd, bool reload);
static int psk__file_parse(struct mosquitto__unpwd **psk_id, const char *psk_file);
static int mosquitto_basic_auth_default(int event, void *event_data, void *userdata);
static int mosquitto_acl_check_default(int event, void *event_data, void *userdata);
@@ -40,7 +39,6 @@ int mosquitto_security_init_default(bool reload)
{
int rc;
char *pwf;
char *pskf = NULL;
UNUSED(reload);
@@ -128,28 +126,8 @@ int mosquitto_security_init_default(bool reload)
}
}
/* Load psk data if required. */
if(db.config->per_listener_settings){
for(int i=0; i<db.config->listener_count; i++){
pskf = db.config->listeners[i].security_options->psk_file;
if(pskf){
rc = psk__file_parse(&db.config->listeners[i].security_options->psk_id, pskf);
if(rc){
log__printf(NULL, MOSQ_LOG_ERR, "Error opening psk file \"%s\".", pskf);
return rc;
}
}
}
}else{
pskf = db.config->security_options.psk_file;
if(pskf){
rc = psk__file_parse(&db.config->security_options.psk_id, pskf);
if(rc){
log__printf(NULL, MOSQ_LOG_ERR, "Error opening psk file \"%s\".", pskf);
return rc;
}
}
}
rc = psk_file__init();
if(rc) return rc;
return MOSQ_ERR_SUCCESS;
}
@@ -171,16 +149,9 @@ int mosquitto_security_cleanup_default(bool reload)
}
}
rc = unpwd__cleanup(&db.config->security_options.psk_id, reload);
rc = psk_file__cleanup();
if(rc != MOSQ_ERR_SUCCESS) return rc;
for(int i=0; i<db.config->listener_count; i++){
if(db.config->listeners[i].security_options->psk_id){
rc = unpwd__cleanup(&db.config->listeners[i].security_options->psk_id, reload);
if(rc != MOSQ_ERR_SUCCESS) return rc;
}
}
if(db.config->per_listener_settings){
for(int i=0; i<db.config->listener_count; i++){
if(db.config->listeners[i].security_options->pid){
@@ -782,18 +753,20 @@ static int pwfile__parse(const char *file, struct mosquitto__unpwd **root)
continue;
}
unpwd->pw.encoded_password = mosquitto_strdup(password);
if(!unpwd->pw.encoded_password){
fclose(pwfile);
if(mosquitto_pw_new(&unpwd->pw, MOSQ_PW_DEFAULT)
|| mosquitto_pw_decode(unpwd->pw, password)){
log__printf(NULL, MOSQ_LOG_NOTICE, "Warning: Unable to decode line in password file '%s'.", file);
mosquitto_pw_cleanup(unpwd->pw);
mosquitto_FREE(unpwd->username);
mosquitto_FREE(unpwd);
mosquitto_FREE(buf);
return MOSQ_ERR_NOMEM;
continue;
}
HASH_ADD_KEYPTR(hh, *root, unpwd->username, strlen(unpwd->username), unpwd);
}else{
log__printf(NULL, MOSQ_LOG_NOTICE, "Warning: Invalid line in password file '%s': %s", file, buf);
mosquitto_pw_cleanup(unpwd->pw);
mosquitto_FREE(unpwd->username);
mosquitto_FREE(unpwd);
}
@@ -810,38 +783,12 @@ static int pwfile__parse(const char *file, struct mosquitto__unpwd **root)
void unpwd__free_item(struct mosquitto__unpwd **unpwd, struct mosquitto__unpwd *item)
{
mosquitto_FREE(item->username);
mosquitto_FREE(item->pw.encoded_password);
mosquitto_pw_cleanup(item->pw);
HASH_DEL(*unpwd, item);
mosquitto_FREE(item);
}
#ifdef WITH_TLS
static int unpwd__decode_passwords(struct mosquitto__unpwd **unpwd)
{
struct mosquitto__unpwd *u, *tmp = NULL;
int rc;
HASH_ITER(hh, *unpwd, u, tmp){
/* Need to decode password into hashed data + salt. */
if(u->pw.encoded_password == NULL){
log__printf(NULL, MOSQ_LOG_ERR, "Error: Missing password hash for user %s, removing entry.", u->username);
unpwd__free_item(unpwd, u);
continue;
}
rc = pw__decode(&u->pw, u->pw.encoded_password);
if(rc){
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to decode password/salt for user %s, removing entry.", u->username);
unpwd__free_item(unpwd, u);
}
}
return MOSQ_ERR_SUCCESS;
}
#endif
static int unpwd__file_parse(struct mosquitto__unpwd **unpwd, const char *password_file)
{
int rc;
@@ -851,42 +798,9 @@ static int unpwd__file_parse(struct mosquitto__unpwd **unpwd, const char *passwo
rc = pwfile__parse(password_file, unpwd);
#if defined(WITH_TLS) || defined(WITH_ARGON2)
if(rc) return rc;
rc = unpwd__decode_passwords(unpwd);
#endif
return rc;
}
static int psk__file_parse(struct mosquitto__unpwd **psk_id, const char *psk_file)
{
int rc;
struct mosquitto__unpwd *u, *tmp = NULL;
if(!db.config || !psk_id) return MOSQ_ERR_INVAL;
/* We haven't been asked to parse a psk file. */
if(!psk_file) return MOSQ_ERR_SUCCESS;
rc = pwfile__parse(psk_file, psk_id);
if(rc) return rc;
HASH_ITER(hh, (*psk_id), u, tmp){
/* Check for hex only digits */
if(!u->pw.encoded_password){
log__printf(NULL, MOSQ_LOG_ERR, "Error: Empty psk for identity \"%s\".", u->username);
return MOSQ_ERR_INVAL;
}
if(strspn(u->pw.encoded_password, "0123456789abcdefABCDEF") < strlen(u->pw.encoded_password)){
log__printf(NULL, MOSQ_LOG_ERR, "Error: psk for identity \"%s\" contains non-hexadecimal characters.", u->username);
return MOSQ_ERR_INVAL;
}
}
return MOSQ_ERR_SUCCESS;
}
static int mosquitto_basic_auth_default(int event, void *event_data, void *userdata)
{
struct mosquitto_evt_basic_auth *ed = event_data;
@@ -910,9 +824,9 @@ static int mosquitto_basic_auth_default(int event, void *event_data, void *userd
HASH_FIND(hh, unpwd_ref, ed->client->username, strlen(ed->client->username), u);
if(u){
if(u->pw.encoded_password){
if(u->pw){
if(ed->client->password){
return pw__verify(&u->pw, ed->client->password);
return mosquitto_pw_verify(u->pw, ed->client->password);
}else{
return MOSQ_ERR_AUTH;
}
@@ -934,7 +848,7 @@ static int unpwd__cleanup(struct mosquitto__unpwd **root, bool reload)
HASH_ITER(hh, *root, u, tmp){
HASH_DEL(*root, u);
mosquitto_FREE(u->pw.encoded_password);
mosquitto_pw_cleanup(u->pw);
mosquitto_FREE(u->username);
mosquitto_FREE(u);
}
@@ -1155,28 +1069,3 @@ int mosquitto_security_apply_default(void)
}
return MOSQ_ERR_SUCCESS;
}
int mosquitto_psk_key_get_default(struct mosquitto *context, const char *hint, const char *identity, char *key, int max_key_len)
{
struct mosquitto__unpwd *u, *tmp = NULL;
struct mosquitto__unpwd *psk_id_ref = NULL;
if(!hint || !identity || !key) return MOSQ_ERR_INVAL;
if(db.config->per_listener_settings){
if(!context->listener) return MOSQ_ERR_INVAL;
psk_id_ref = context->listener->security_options->psk_id;
}else{
psk_id_ref = db.config->security_options.psk_id;
}
if(!psk_id_ref) return MOSQ_ERR_PLUGIN_IGNORE;
HASH_ITER(hh, psk_id_ref, u, tmp){
if(!strcmp(u->username, identity)){
strncpy(key, u->pw.encoded_password, (size_t)max_key_len);
return MOSQ_ERR_SUCCESS;
}
}
return MOSQ_ERR_AUTH;
}
+1 -1
View File
@@ -27,7 +27,7 @@ connack_packet = mosq_test.gen_connack(rc=0)
env = os.environ
env["MOSQUITTO_DYNSEC_PASSWORD"] = "adminadminadmin"
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port, env=env)
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port, env=env, timeout=3)
try:
sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=5, port=port)
+1 -1
View File
@@ -28,7 +28,7 @@ rc = 1
connect_packet = mosq_test.gen_connect("ctrl-test", username="admin", password="adminadminadmin")
connack_packet = mosq_test.gen_connack(rc=0)
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port, timeout=3)
try:
sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=5, port=port)
+1 -1
View File
@@ -22,7 +22,7 @@ except FileExistsError:
pass
rc = 1
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port, timeout=3)
with open(f"{port}/dynamic-security.json.pw", "r") as f:
data = f.readlines()
+6 -8
View File
@@ -60,12 +60,10 @@ def listen_sock(port):
sock.listen(5)
return sock
def start_broker(filename, cmd=None, port=0, use_conf=False, expect_fail=False, expect_fail_log=None, nolog=False, checkhost="localhost", env=None, check_port=True, cmd_args=None):
def start_broker(filename, cmd=None, port=0, use_conf=False, expect_fail=False, expect_fail_log=None, nolog=False, checkhost="localhost", env=None, check_port=True, cmd_args=None, timeout=0.1):
global vg_index
global vg_logfiles
delay = 0.1
if use_conf:
cmd = [get_build_root() + '/src/mosquitto', '-v', '-c', filename.replace('.py', '.conf')]
else:
@@ -86,7 +84,7 @@ def start_broker(filename, cmd=None, port=0, use_conf=False, expect_fail=False,
cmd = ['valgrind', '-q', '--track-fds=yes', '--trace-children=yes', '--leak-check=full', '--show-leak-kinds=all', '--log-file='+logfile] + cmd
vg_logfiles.append(logfile)
vg_index += 1
delay = 1
timeout = 1
if cmd_args:
cmd.extend(cmd_args)
@@ -102,7 +100,7 @@ def start_broker(filename, cmd=None, port=0, use_conf=False, expect_fail=False,
if expect_fail:
try:
broker.wait(delay*10)
broker.wait(timeout*10)
if expect_fail_log is not None:
(_, stde) = broker.communicate()
if expect_fail_log not in stde.decode('utf-8'):
@@ -119,9 +117,9 @@ def start_broker(filename, cmd=None, port=0, use_conf=False, expect_fail=False,
return broker
assert port != 0
for i in range(0, 20):
time.sleep(delay)
time.sleep(timeout)
c = None
try:
c = socket.create_connection((checkhost, port))
@@ -134,7 +132,7 @@ def start_broker(filename, cmd=None, port=0, use_conf=False, expect_fail=False,
return broker
if expect_fail == False:
outs, errs = broker.communicate(timeout=1)
outs, errs = broker.communicate(timeout=timeout)
print("FAIL: unable to start broker: %s" % errs)
raise IOError
else: