diff --git a/.github/workflows/mosquitto-make-asan.yml b/.github/workflows/mosquitto-make-asan.yml index 1ed6acfa..b4cc7dc6 100644 --- a/.github/workflows/mosquitto-make-asan.yml +++ b/.github/workflows/mosquitto-make-asan.yml @@ -45,4 +45,4 @@ jobs: - name: make test run: | - make WITH_ASAN=yes ptest + make WITH_ASAN=yes test diff --git a/.github/workflows/mosquitto-make.yml b/.github/workflows/mosquitto-make.yml index 3b4b4634..b16c988f 100644 --- a/.github/workflows/mosquitto-make.yml +++ b/.github/workflows/mosquitto-make.yml @@ -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 diff --git a/apps/mosquitto_ctrl/CMakeLists.txt b/apps/mosquitto_ctrl/CMakeLists.txt index 4ce53100..91a0f508 100644 --- a/apps/mosquitto_ctrl/CMakeLists.txt +++ b/apps/mosquitto_ctrl/CMakeLists.txt @@ -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 diff --git a/apps/mosquitto_ctrl/Makefile b/apps/mosquitto_ctrl/Makefile index e1039c96..911edd11 100644 --- a/apps/mosquitto_ctrl/Makefile +++ b/apps/mosquitto_ctrl/Makefile @@ -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 diff --git a/apps/mosquitto_ctrl/dynsec.c b/apps/mosquitto_ctrl/dynsec.c index 3079c4e2..b545eb55 100644 --- a/apps/mosquitto_ctrl/dynsec.c +++ b/apps/mosquitto_ctrl/dynsec.c @@ -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){ diff --git a/apps/mosquitto_ctrl/dynsec_client.c b/apps/mosquitto_ctrl/dynsec_client.c index 55e37a6c..8a1a9c41 100644 --- a/apps/mosquitto_ctrl/dynsec_client.c +++ b/apps/mosquitto_ctrl/dynsec_client.c @@ -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; } } diff --git a/apps/mosquitto_ctrl/dynsec_group.c b/apps/mosquitto_ctrl/dynsec_group.c index 912e051f..93823cac 100644 --- a/apps/mosquitto_ctrl/dynsec_group.c +++ b/apps/mosquitto_ctrl/dynsec_group.c @@ -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) { diff --git a/apps/mosquitto_ctrl/dynsec_role.c b/apps/mosquitto_ctrl/dynsec_role.c index 55efab52..a4fc49c0 100644 --- a/apps/mosquitto_ctrl/dynsec_role.c +++ b/apps/mosquitto_ctrl/dynsec_role.c @@ -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) { diff --git a/apps/mosquitto_passwd/CMakeLists.txt b/apps/mosquitto_passwd/CMakeLists.txt index de1f5081..93047c68 100644 --- a/apps/mosquitto_passwd/CMakeLists.txt +++ b/apps/mosquitto_passwd/CMakeLists.txt @@ -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 diff --git a/apps/mosquitto_passwd/Makefile b/apps/mosquitto_passwd/Makefile index 9ff90f00..cfcc3f95 100644 --- a/apps/mosquitto_passwd/Makefile +++ b/apps/mosquitto_passwd/Makefile @@ -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" diff --git a/apps/mosquitto_passwd/mosquitto_passwd.c b/apps/mosquitto_passwd/mosquitto_passwd.c index a8a6b51e..50c70e05 100644 --- a/apps/mosquitto_passwd/mosquitto_passwd.c +++ b/apps/mosquitto_passwd/mosquitto_passwd.c @@ -29,7 +29,6 @@ Contributors: #include "mosquitto.h" #include "get_password.h" -#include "password_mosq.h" #ifdef WIN32 # include @@ -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; diff --git a/common/password_mosq.h b/common/password_mosq.h deleted file mode 100644 index 45d8a92c..00000000 --- a/common/password_mosq.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef PASSWORD_MOSQ_H -#define PASSWORD_MOSQ_H -/* -Copyright (c) 2012-2021 Roger Light - -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 - -#ifdef WITH_TLS -# include -# 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 diff --git a/config.mk b/config.mk index 9103c094..4e227984 100644 --- a/config.mk +++ b/config.mk @@ -298,4 +298,5 @@ endif ifeq ($(WITH_ARGON2),yes) LOCAL_CPPFLAGS+=-DWITH_ARGON2 LIB_ARGON2=-largon2 + LIBMOSQ_COMMON+=${LIB_ARGON2} endif diff --git a/fuzzing/apps/db_dump/Makefile b/fuzzing/apps/db_dump/Makefile index b45971fc..e139a5f8 100644 --- a/fuzzing/apps/db_dump/Makefile +++ b/fuzzing/apps/db_dump/Makefile @@ -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) diff --git a/fuzzing/apps/mosquitto_passwd/Makefile b/fuzzing/apps/mosquitto_passwd/Makefile index f6c85ebb..31533c22 100644 --- a/fuzzing/apps/mosquitto_passwd/Makefile +++ b/fuzzing/apps/mosquitto_passwd/Makefile @@ -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) diff --git a/fuzzing/broker/Makefile b/fuzzing/broker/Makefile index 1474508b..51ac7d53 100644 --- a/fuzzing/broker/Makefile +++ b/fuzzing/broker/Makefile @@ -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) diff --git a/fuzzing/lib/Makefile b/fuzzing/lib/Makefile index 36e747d9..5ee17f00 100644 --- a/fuzzing/lib/Makefile +++ b/fuzzing/lib/Makefile @@ -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) diff --git a/fuzzing/plugins/dynamic-security/Makefile b/fuzzing/plugins/dynamic-security/Makefile index f3ec379a..b9be3c3f 100644 --- a/fuzzing/plugins/dynamic-security/Makefile +++ b/fuzzing/plugins/dynamic-security/Makefile @@ -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) diff --git a/include/mosquitto/libcommon.h b/include/mosquitto/libcommon.h index 2f7122c0..04db9111 100644 --- a/include/mosquitto/libcommon.h +++ b/include/mosquitto/libcommon.h @@ -39,6 +39,7 @@ extern "C" { #include #include #include +#include #include #include #include diff --git a/include/mosquitto/libcommon_password.h b/include/mosquitto/libcommon_password.h new file mode 100644 index 00000000..e98c5ffb --- /dev/null +++ b/include/mosquitto/libcommon_password.h @@ -0,0 +1,58 @@ +/* +Copyright (c) 2010-2021 Roger Light + +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 + diff --git a/lib/Makefile b/lib/Makefile index e48ad3cb..d7ef9b93 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -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:= # ------------------------------------------ diff --git a/libcommon/CMakeLists.txt b/libcommon/CMakeLists.txt index 23f4cc34..28259f74 100644 --- a/libcommon/CMakeLists.txt +++ b/libcommon/CMakeLists.txt @@ -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 diff --git a/libcommon/Makefile b/libcommon/Makefile index 2881a1ce..f14609d1 100644 --- a/libcommon/Makefile +++ b/libcommon/Makefile @@ -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 \ diff --git a/common/password_mosq.c b/libcommon/password_common.c similarity index 76% rename from common/password_mosq.c rename to libcommon/password_common.c index a610adc1..db7a12c8 100644 --- a/common/password_mosq.c +++ b/libcommon/password_common.c @@ -18,33 +18,23 @@ Contributors: #include "config.h" +#include +#include + #ifdef WITH_TLS # include # include # include +# define HASH_LEN EVP_MAX_MD_SIZE #endif -#include #include "mosquitto.h" -#include "password_mosq.h" -#ifdef WIN32 -# include -# include -# ifndef __cplusplus -# if defined(_MSC_VER) && _MSC_VER < 1900 -# define bool char -# define true 1 -# define false 0 -# else -# include -# endif -# endif -# define snprintf sprintf_s -# include -# include +#ifdef WITH_TLS +# define HASH_LEN EVP_MAX_MD_SIZE #else -# include + /* 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); } } diff --git a/plugins/dynamic-security/CMakeLists.txt b/plugins/dynamic-security/CMakeLists.txt index ddd7bf22..59dad8fd 100644 --- a/plugins/dynamic-security/CMakeLists.txt +++ b/plugins/dynamic-security/CMakeLists.txt @@ -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 diff --git a/plugins/dynamic-security/Makefile b/plugins/dynamic-security/Makefile index 3821afb5..5ca49d09 100644 --- a/plugins/dynamic-security/Makefile +++ b/plugins/dynamic-security/Makefile @@ -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 diff --git a/plugins/dynamic-security/auth.c b/plugins/dynamic-security/auth.c index 5820155d..9b5dd10c 100644 --- a/plugins/dynamic-security/auth.c +++ b/plugins/dynamic-security/auth.c @@ -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; diff --git a/plugins/dynamic-security/clients.c b/plugins/dynamic-security/clients.c index 3f3ffd60..85aabbf0 100644 --- a/plugins/dynamic-security/clients.c +++ b/plugins/dynamic-security/clients.c @@ -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) diff --git a/plugins/dynamic-security/config_init.c b/plugins/dynamic-security/config_init.c index 43692f57..4ad79b13 100644 --- a/plugins/dynamic-security/config_init.c +++ b/plugins/dynamic-security/config_init.c @@ -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; } diff --git a/plugins/dynamic-security/dynamic_security.h b/plugins/dynamic-security/dynamic_security.h index 07316e59..ff0c3247 100644 --- a/plugins/dynamic-security/dynamic_security.h +++ b/plugins/dynamic-security/dynamic_security.h @@ -21,7 +21,6 @@ Contributors: #include #include #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; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1458b782..dae22bd5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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() diff --git a/src/Makefile b/src/Makefile index d0302bd9..1a32fc44 100644 --- a/src/Makefile +++ b/src/Makefile @@ -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 $@ diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 7517ce4c..ef1a2e66 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -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); diff --git a/src/psk_file.c b/src/psk_file.c new file mode 100644 index 00000000..0cc18ac7 --- /dev/null +++ b/src/psk_file.c @@ -0,0 +1,256 @@ +/* +Copyright (c) 2011-2021 Roger Light + +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 +#include +#include + +#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; ilistener_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; ilistener_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; +} diff --git a/src/security_default.c b/src/security_default.c index e5f58ddf..7259cff9 100644 --- a/src/security_default.c +++ b/src/security_default.c @@ -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; ilistener_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; ilistener_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; ilistener_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; -} diff --git a/test/broker/14-dynsec-config-init-env.py b/test/broker/14-dynsec-config-init-env.py index 474b185c..6c682109 100755 --- a/test/broker/14-dynsec-config-init-env.py +++ b/test/broker/14-dynsec-config-init-env.py @@ -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) diff --git a/test/broker/14-dynsec-config-init-file.py b/test/broker/14-dynsec-config-init-file.py index 5bd8e56c..abbd3ae2 100755 --- a/test/broker/14-dynsec-config-init-file.py +++ b/test/broker/14-dynsec-config-init-file.py @@ -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) diff --git a/test/broker/14-dynsec-config-init-random.py b/test/broker/14-dynsec-config-init-random.py index 7e7a6dde..57fbf38b 100755 --- a/test/broker/14-dynsec-config-init-random.py +++ b/test/broker/14-dynsec-config-init-random.py @@ -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() diff --git a/test/mosq_test.py b/test/mosq_test.py index 5e9e0c2d..fdb850c3 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -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: