diff --git a/ChangeLog.txt b/ChangeLog.txt index c0666b30..96ec3db8 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,8 @@ +Security: +- Fix CVE-xxxx-xxxx. If a SIGHUP is sent to the broker when there are no more + file descriptors, then opening the configuration file will fail and security + settings will be set back to their default values. + Broker: - Use constant time memcmp for password comparisons. - Fix incorrect PSK key being used if it had leading zeroes. diff --git a/src/conf.c b/src/conf.c index 274140a3..c40232e0 100644 --- a/src/conf.c +++ b/src/conf.c @@ -129,7 +129,7 @@ static int _conf_attempt_resolve(const char *host, const char *text, int log, co return MOSQ_ERR_SUCCESS; } -static void _config_init_reload(struct mqtt3_config *config) +static void _config_init_reload(struct mosquitto_db *db, struct mqtt3_config *config) { int i; /* Set defaults */ @@ -165,7 +165,7 @@ static void _config_init_reload(struct mqtt3_config *config) #else config->log_facility = LOG_DAEMON; config->log_dest = MQTT3_LOG_STDERR; - if(config->verbose){ + if(db->verbose){ config->log_type = INT_MAX; }else{ config->log_type = MOSQ_LOG_ERR | MOSQ_LOG_WARNING | MOSQ_LOG_NOTICE | MOSQ_LOG_INFO; @@ -197,11 +197,10 @@ static void _config_init_reload(struct mqtt3_config *config) } } -void mqtt3_config_init(struct mqtt3_config *config) +void mqtt3_config_init(struct mosquitto_db *db, struct mqtt3_config *config) { memset(config, 0, sizeof(struct mqtt3_config)); - _config_init_reload(config); - config->config_file = NULL; + _config_init_reload(db, config); config->daemon = false; config->default_listener.host = NULL; config->default_listener.port = 0; @@ -234,7 +233,6 @@ void mqtt3_config_init(struct mqtt3_config *config) #endif config->auth_plugin = NULL; config->auth_plugin_deny_special_chars = true; - config->verbose = false; config->message_size_limit = 0; } @@ -248,7 +246,6 @@ void mqtt3_config_cleanup(struct mqtt3_config *config) if(config->acl_file) _mosquitto_free(config->acl_file); if(config->auto_id_prefix) _mosquitto_free(config->auto_id_prefix); if(config->clientid_prefixes) _mosquitto_free(config->clientid_prefixes); - if(config->config_file) _mosquitto_free(config->config_file); if(config->password_file) _mosquitto_free(config->password_file); if(config->persistence_location) _mosquitto_free(config->persistence_location); if(config->persistence_file) _mosquitto_free(config->persistence_file); @@ -354,7 +351,7 @@ static void print_usage(void) printf("\nSee http://mosquitto.org/ for more information.\n\n"); } -int mqtt3_config_parse_args(struct mqtt3_config *config, int argc, char *argv[]) +int mqtt3_config_parse_args(struct mosquitto_db *db, struct mqtt3_config *config, int argc, char *argv[]) { int i; int port_tmp; @@ -362,13 +359,9 @@ int mqtt3_config_parse_args(struct mqtt3_config *config, int argc, char *argv[]) for(i=1; iconfig_file = _mosquitto_strdup(argv[i+1]); - if(!config->config_file){ - _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); - return MOSQ_ERR_NOMEM; - } + db->config_file = argv[i+1]; - if(mqtt3_config_read(config, false)){ + if(mqtt3_config_read(db, config, false)){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open configuration file."); return MOSQ_ERR_INVAL; } @@ -400,7 +393,7 @@ int mqtt3_config_parse_args(struct mqtt3_config *config, int argc, char *argv[]) } i++; }else if(!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")){ - config->verbose = true; + db->verbose = true; }else{ fprintf(stderr, "Error: Unknown option '%s'.\n",argv[i]); print_usage(); @@ -475,22 +468,87 @@ int mqtt3_config_parse_args(struct mqtt3_config *config, int argc, char *argv[]) if(!config->user){ config->user = "mosquitto"; } - if(config->verbose){ + if(db->verbose){ config->log_type = INT_MAX; } return MOSQ_ERR_SUCCESS; } -int mqtt3_config_read(struct mqtt3_config *config, bool reload) +/* Copy reloaded config into existing config struct */ +void config__copy(struct mqtt3_config *src, struct mqtt3_config *dest) +{ + _mosquitto_free(dest->acl_file); + dest->acl_file = src->acl_file; + + dest->allow_anonymous = src->allow_anonymous; + dest->allow_duplicate_messages = src->allow_duplicate_messages; + dest->allow_zero_length_clientid = src->allow_zero_length_clientid; + + _mosquitto_free(dest->auto_id_prefix); + dest->auto_id_prefix = src->auto_id_prefix; + dest->auto_id_prefix_len = src->auto_id_prefix_len; + + dest->autosave_interval = src->autosave_interval; + dest->autosave_on_changes = src->autosave_on_changes; + + _mosquitto_free(dest->clientid_prefixes); + dest->clientid_prefixes = src->clientid_prefixes; + + dest->connection_messages = src->connection_messages; + dest->log_dest = src->log_dest; + dest->log_facility = src->log_facility; + dest->log_type = src->log_type; + dest->log_timestamp = src->log_timestamp; + + _mosquitto_free(dest->log_file); + dest->log_file = src->log_file; + + dest->message_size_limit = src->message_size_limit; + + _mosquitto_free(dest->password_file); + dest->password_file = src->password_file; + + dest->persistence = src->persistence; + + _mosquitto_free(dest->persistence_location); + dest->persistence_location = src->persistence_location; + + _mosquitto_free(dest->persistence_file); + dest->persistence_file = src->persistence_file; + + _mosquitto_free(dest->persistence_filepath); + dest->persistence_filepath = src->persistence_filepath; + + dest->persistent_client_expiration = src->persistent_client_expiration; + + _mosquitto_free(dest->psk_file); + dest->psk_file = src->psk_file; + + dest->queue_qos0_messages = src->queue_qos0_messages; + dest->retry_interval = src->retry_interval; + dest->sys_interval = src->sys_interval; + dest->upgrade_outgoing_qos = src->upgrade_outgoing_qos; + +#ifdef WITH_WEBSOCKETS + dest->websockets_log_level = src->websockets_log_level; +#endif +} + +int mqtt3_config_read(struct mosquitto_db *db, struct mqtt3_config *config, bool reload) { int rc = MOSQ_ERR_SUCCESS; struct config_recurse cr; int lineno; int len; + struct mqtt3_config config_reload; #ifdef WITH_BRIDGE int i; #endif + if(reload){ + memset(&config_reload, 0, sizeof(struct mqtt3_config)); + } + cr.log_dest = MQTT3_LOG_NONE; cr.log_dest_set = 0; cr.log_type = MOSQ_LOG_NONE; @@ -498,18 +556,24 @@ int mqtt3_config_read(struct mqtt3_config *config, bool reload) cr.max_inflight_messages = 20; cr.max_queued_messages = 100; - if(!config->config_file) return 0; + if(!db->config_file) return 0; if(reload){ /* Re-initialise appropriate config vars to default for reload. */ - _config_init_reload(config); + _config_init_reload(db, &config_reload); + rc = _config_read_file(&config_reload, reload, db->config_file, &cr, 0, &lineno); + }else{ + rc = _config_read_file(config, reload, db->config_file, &cr, 0, &lineno); } - rc = _config_read_file(config, reload, config->config_file, &cr, 0, &lineno); if(rc){ - _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error found at %s:%d.", config->config_file, lineno); + _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error found at %s:%d.", db->config_file, lineno); return rc; } + if(reload){ + config__copy(&config_reload, config); + } + #ifdef WITH_PERSISTENCE if(config->persistence){ if(!config->persistence_file){ @@ -561,7 +625,7 @@ int mqtt3_config_read(struct mqtt3_config *config, bool reload) if(cr.log_dest_set){ config->log_dest = cr.log_dest; } - if(config->verbose){ + if(db->verbose){ config->log_type = INT_MAX; }else if(cr.log_type_set){ config->log_type = cr.log_type; diff --git a/src/loop.c b/src/loop.c index bf4876bc..7c505896 100644 --- a/src/loop.c +++ b/src/loop.c @@ -390,7 +390,7 @@ int mosquitto_main_loop(struct mosquitto_db *db, mosq_sock_t *listensock, int li #endif if(flag_reload){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Reloading config."); - mqtt3_config_read(db->config, true); + mqtt3_config_read(db, db->config, true); mosquitto_security_cleanup(db, true); mosquitto_security_init(db, true); mosquitto_security_apply(db); diff --git a/src/mosquitto.c b/src/mosquitto.c index b28150ce..caf674fc 100644 --- a/src/mosquitto.c +++ b/src/mosquitto.c @@ -259,8 +259,8 @@ int main(int argc, char *argv[]) _mosquitto_net_init(); - mqtt3_config_init(&config); - rc = mqtt3_config_parse_args(&config, argc, argv); + mqtt3_config_init(&int_db, &config); + rc = mqtt3_config_parse_args(&int_db, &config, argc, argv); if(rc != MOSQ_ERR_SUCCESS) return rc; int_db.config = &config; @@ -292,8 +292,8 @@ int main(int argc, char *argv[]) return rc; } _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "mosquitto version %s (build date %s) starting", VERSION, TIMESTAMP); - if(config.config_file){ - _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Config loaded from %s.", config.config_file); + if(int_db.config_file){ + _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Config loaded from %s.", int_db.config_file); }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Using default config."); } diff --git a/src/mosquitto_broker.h b/src/mosquitto_broker.h index f33007c8..57543a61 100644 --- a/src/mosquitto_broker.h +++ b/src/mosquitto_broker.h @@ -101,7 +101,6 @@ struct _mqtt3_listener { }; struct mqtt3_config { - char *config_file; char *acl_file; bool allow_anonymous; bool allow_duplicate_messages; @@ -137,7 +136,6 @@ struct mqtt3_config { int sys_interval; bool upgrade_outgoing_qos; char *user; - bool verbose; #ifdef WITH_WEBSOCKETS int websockets_log_level; bool have_websockets_listener; @@ -260,9 +258,11 @@ struct mosquitto_db{ int bridge_count; #endif int msg_store_count; + char *config_file; struct mqtt3_config *config; int persistence_changes; struct _mosquitto_auth_plugin auth_plugin; + bool verbose; #ifdef WITH_SYS_TREE int subscription_count; int retained_count; @@ -365,14 +365,14 @@ struct mosquitto_db *_mosquitto_get_db(void); * Config functions * ============================================================ */ /* Initialise config struct to default values. */ -void mqtt3_config_init(struct mqtt3_config *config); +void mqtt3_config_init(struct mosquitto_db *db, struct mqtt3_config *config); /* Parse command line options into config. */ -int mqtt3_config_parse_args(struct mqtt3_config *config, int argc, char *argv[]); +int mqtt3_config_parse_args(struct mosquitto_db *db, struct mqtt3_config *config, int argc, char *argv[]); /* Read configuration data from config->config_file into config. * If reload is true, don't process config options that shouldn't be reloaded (listeners etc) * Returns 0 on success, 1 if there is a configuration error or if a file cannot be opened. */ -int mqtt3_config_read(struct mqtt3_config *config, bool reload); +int mqtt3_config_read(struct mosquitto_db *db, struct mqtt3_config *config, bool reload); /* Free all config data. */ void mqtt3_config_cleanup(struct mqtt3_config *config);