From fe5dba58874fb80d02f7313f323741b67cc9f314 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 2 Jul 2014 00:09:50 +0100 Subject: [PATCH] Add use_username_as_clientid. --- ChangeLog.txt | 5 +++++ man/mosquitto.conf.5.xml | 19 +++++++++++++++++++ mosquitto.conf | 20 ++++++++++++++++++++ src/conf.c | 9 +++++++++ src/mosquitto_broker.h | 1 + src/read_handle_server.c | 15 +++++++++++++++ 6 files changed, 69 insertions(+) diff --git a/ChangeLog.txt b/ChangeLog.txt index c0bd0cb4..c9dfa9cd 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -13,6 +13,8 @@ Important changes: - When a durable client reconnects, its queued messages are now checked against ACLs in case of a change in username/ACL state since it last connected. +- New use_username_as_clientid option on the broker, for preventing hijacking + of a client id. Broker: @@ -37,6 +39,9 @@ Broker: provided at the command line. - Removed $SYS/broker/changeset. This was intended for use with debugging, but in practice is of no use. +- Add support for use_username_as_clientid which can be used with + authentication to restrict ownership of client ids and hence prevent one + client disconnecting another by using the same client id. Clients: - Both clients can now load default configuration options from a file. diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index f7b711ab..a4524448 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -667,6 +667,25 @@ Not reloaded on reload signal. + + [ true | false ] + + Set to + true to replace the clientid that a client + connected with with its username. This allows + authentication to be tied to the clientid, which + means that it is possible to prevent one client + disconnecting another by using the same + clientid. Defaults to false. + If a client connects with no username it will be + disconnected as not authorised when this option is + set to true. Do not use in conjunction with + . + See also + . + Not reloaded on reload signal. + + diff --git a/mosquitto.conf b/mosquitto.conf index 84f5f57b..c5c1c3cd 100644 --- a/mosquitto.conf +++ b/mosquitto.conf @@ -150,6 +150,16 @@ # only the cafile, certfile, keyfile and ciphers options are supported. #protocol mqtt +# Set use_username_as_clientid to true to replace the clientid that a client +# connected with with its username. This allows authentication to be tied to +# the clientid, which means that it is possible to prevent one client +# disconnecting another by using the same clientid. +# If a client connects with no username it will be disconnected as not +# authorised when this option is set to true. +# Do not use in conjunction with clientid_prefixes. +# See also use_identity_as_username. +#use_username_as_clientid + # ----------------------------------------------------------------- # Certificate based SSL/TLS support # ----------------------------------------------------------------- @@ -276,6 +286,16 @@ # This can be either mqtt or websockets. #protocol mqtt +# Set use_username_as_clientid to true to replace the clientid that a client +# connected with with its username. This allows authentication to be tied to +# the clientid, which means that it is possible to prevent one client +# disconnecting another by using the same clientid. +# If a client connects with no username it will be disconnected as not +# authorised when this option is set to true. +# Do not use in conjunction with clientid_prefixes. +# See also use_identity_as_username. +#use_username_as_clientid + # ----------------------------------------------------------------- # Certificate based SSL/TLS support # ----------------------------------------------------------------- diff --git a/src/conf.c b/src/conf.c index 0fe6d300..3203ba5f 100644 --- a/src/conf.c +++ b/src/conf.c @@ -178,6 +178,7 @@ void mqtt3_config_init(struct mqtt3_config *config) config->default_listener.sock_count = 0; config->default_listener.client_count = 0; config->default_listener.protocol = mp_mqtt; + config->default_listener.use_username_as_clientid = false; #ifdef WITH_TLS config->default_listener.tls_version = NULL; config->default_listener.cafile = NULL; @@ -378,6 +379,7 @@ int mqtt3_config_parse_args(struct mqtt3_config *config, int argc, char *argv[]) || config->default_listener.crlfile || config->default_listener.use_identity_as_username #endif + || config->default_listener.use_username_as_clientid || config->default_listener.host || config->default_listener.port || config->default_listener.max_connections != -1 @@ -412,6 +414,7 @@ int mqtt3_config_parse_args(struct mqtt3_config *config, int argc, char *argv[]) config->listeners[config->listener_count-1].socks = NULL; config->listeners[config->listener_count-1].sock_count = 0; config->listeners[config->listener_count-1].client_count = 0; + config->listeners[config->listener_count-1].use_username_as_clientid = config->default_listener.use_username_as_clientid; #ifdef WITH_TLS config->listeners[config->listener_count-1].tls_version = config->default_listener.tls_version; config->listeners[config->listener_count-1].cafile = config->default_listener.cafile; @@ -1763,6 +1766,12 @@ int _config_read_file_core(struct mqtt3_config *config, bool reload, const char #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS support not available."); #endif + }else if(!strcmp(token, "user")){ + if(reload) continue; // Drop privileges user not valid for reloading. + if(_conf_parse_string(&token, "user", &config->user, saveptr)) return MOSQ_ERR_INVAL; + }else if(!strcmp(token, "use_username_as_clientid")){ + if(reload) continue; // Listeners not valid for reloading. + if(_conf_parse_bool(&token, "use_username_as_clientid", &cur_listener->use_username_as_clientid, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "user")){ if(reload) continue; // Drop privileges user not valid for reloading. if(_conf_parse_string(&token, "user", &config->user, saveptr)) return MOSQ_ERR_INVAL; diff --git a/src/mosquitto_broker.h b/src/mosquitto_broker.h index d62e3e5b..1f0568e8 100644 --- a/src/mosquitto_broker.h +++ b/src/mosquitto_broker.h @@ -59,6 +59,7 @@ struct _mqtt3_listener { int sock_count; int client_count; enum mosquitto_protocol protocol; + bool use_username_as_clientid; #ifdef WITH_TLS char *cafile; char *capath; diff --git a/src/read_handle_server.c b/src/read_handle_server.c index 3d51f17d..81466255 100644 --- a/src/read_handle_server.c +++ b/src/read_handle_server.c @@ -387,6 +387,21 @@ int mqtt3_handle_connect(struct mosquitto_db *db, struct mosquitto *context) } #endif + if(context->listener && context->listener->use_username_as_clientid){ + if(context->username){ + _mosquitto_free(client_id); + client_id = _mosquitto_strdup(context->username); + if(!client_id){ + rc = MOSQ_ERR_NOMEM; + goto handle_connect_error; + } + }else{ + _mosquitto_send_connack(context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); + rc = MOSQ_ERR_SUCCESS; + goto handle_connect_error; + } + } + /* Find if this client already has an entry. This must be done *after* any security checks. */ HASH_FIND(hh_id, db->contexts_by_id, client_id, strlen(client_id), found_context); if(found_context){