Add use_username_as_clientid.

This commit is contained in:
Roger A. Light 2014-07-02 00:09:50 +01:00
parent cabcada849
commit fe5dba5887
6 changed files with 69 additions and 0 deletions

View File

@ -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.

View File

@ -667,6 +667,25 @@
<para>Not reloaded on reload signal.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>use_username_as_clientid</option> [ true | false ]</term>
<listitem>
<para>Set <option>use_username_as_clientid</option> 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.</para>
<para>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
<option>clientid_prefixes</option>.</para>
<para>See also
<option>use_identity_as_username</option>.</para>
<para>Not reloaded on reload signal.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect2>
<refsect2>

View File

@ -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
# -----------------------------------------------------------------

View File

@ -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;

View File

@ -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;

View File

@ -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){