2014-05-07 22:27:00 +00:00
/*
2018-04-11 14:24:29 +00:00
Copyright ( c ) 2009 - 2018 Roger Light < roger @ atchoo . org >
2014-05-07 22:27:00 +00:00
All rights reserved . This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1 .0
and Eclipse Distribution License v1 .0 which accompany this distribution .
2016-03-06 22:30:17 +00:00
2014-05-07 22:27:00 +00:00
The Eclipse Public License is available at
http : //www.eclipse.org/legal/epl-v10.html
and the Eclipse Distribution License is available at
http : //www.eclipse.org/org/documents/edl-v10.php.
2016-03-06 22:30:17 +00:00
2014-05-07 22:27:00 +00:00
Contributors :
Roger Light - initial implementation and documentation .
*/
2018-08-16 10:14:51 +00:00
# include "config.h"
2014-05-07 22:27:00 +00:00
# include <stdio.h>
# include <string.h>
2016-07-08 09:10:04 +00:00
# include "mosquitto_broker_internal.h"
2018-08-29 21:26:16 +00:00
# include "mqtt_protocol.h"
2015-04-29 20:37:47 +00:00
# include "memory_mosq.h"
# include "packet_mosq.h"
2018-10-02 15:27:40 +00:00
# include "property_mosq.h"
2015-04-29 20:37:47 +00:00
# include "send_mosq.h"
2015-05-16 11:25:35 +00:00
# include "sys_tree.h"
2015-04-29 20:37:47 +00:00
# include "time_mosq.h"
# include "tls_mosq.h"
# include "util_mosq.h"
2014-05-07 22:27:00 +00:00
2014-06-15 00:07:05 +00:00
# ifdef WITH_UUID
# include <uuid / uuid.h>
# endif
2014-06-30 05:58:56 +00:00
# ifdef WITH_WEBSOCKETS
2015-12-19 01:21:17 +00:00
# include <libwebsockets.h>
2014-06-30 05:58:56 +00:00
# endif
2018-03-18 21:07:04 +00:00
static char * client_id_gen ( struct mosquitto_db * db , int * idlen , const char * auto_id_prefix , int auto_id_prefix_len )
2014-06-14 23:37:30 +00:00
{
char * client_id ;
2014-06-15 00:07:05 +00:00
# ifdef WITH_UUID
uuid_t uuid ;
# else
2014-06-14 23:37:30 +00:00
int i ;
2014-06-15 00:07:05 +00:00
# endif
2014-06-14 23:37:30 +00:00
2014-06-15 00:07:05 +00:00
# ifdef WITH_UUID
2018-03-18 21:07:04 +00:00
* idlen = 36 + auto_id_prefix_len ;
2018-02-13 12:19:34 +00:00
# else
2018-03-18 21:07:04 +00:00
* idlen = 64 + auto_id_prefix_len ;
2018-02-13 12:19:34 +00:00
# endif
client_id = ( char * ) mosquitto__calloc ( ( * idlen ) + 1 , sizeof ( char ) ) ;
2014-06-15 00:07:05 +00:00
if ( ! client_id ) {
return NULL ;
}
2018-03-18 21:07:04 +00:00
if ( auto_id_prefix ) {
memcpy ( client_id , auto_id_prefix , auto_id_prefix_len ) ;
2014-06-15 00:07:05 +00:00
}
2018-02-13 12:19:34 +00:00
# ifdef WITH_UUID
2014-06-15 00:07:05 +00:00
uuid_generate_random ( uuid ) ;
2018-03-18 21:07:04 +00:00
uuid_unparse_lower ( uuid , & client_id [ auto_id_prefix_len ] ) ;
2014-06-15 00:07:05 +00:00
# else
2014-06-14 23:37:30 +00:00
for ( i = 0 ; i < 64 ; i + + ) {
2018-03-18 21:07:04 +00:00
client_id [ i + auto_id_prefix_len ] = ( rand ( ) % 73 ) + 48 ;
2014-06-14 23:37:30 +00:00
}
client_id [ i ] = ' \0 ' ;
2014-06-15 00:07:05 +00:00
# endif
2014-06-14 23:37:30 +00:00
return client_id ;
}
2016-04-18 15:48:11 +00:00
/* Remove any queued messages that are no longer allowed through ACL,
* assuming a possible change of username . */
void connection_check_acl ( struct mosquitto_db * db , struct mosquitto * context , struct mosquitto_client_msg * * msgs )
{
struct mosquitto_client_msg * msg_tail , * msg_prev ;
msg_tail = * msgs ;
msg_prev = NULL ;
while ( msg_tail ) {
if ( msg_tail - > direction = = mosq_md_out ) {
2018-05-22 14:51:26 +00:00
if ( mosquitto_acl_check ( db , context , msg_tail - > store - > topic ,
msg_tail - > store - > payloadlen , UHPA_ACCESS ( msg_tail - > store - > payload , msg_tail - > store - > payloadlen ) ,
msg_tail - > store - > qos , msg_tail - > store - > retain , MOSQ_ACL_READ ) ! = MOSQ_ERR_SUCCESS ) {
2016-04-18 15:48:11 +00:00
db__msg_store_deref ( db , & msg_tail - > store ) ;
if ( msg_prev ) {
msg_prev - > next = msg_tail - > next ;
mosquitto__free ( msg_tail ) ;
msg_tail = msg_prev - > next ;
} else {
* msgs = ( * msgs ) - > next ;
mosquitto__free ( msg_tail ) ;
msg_tail = ( * msgs ) ;
}
// XXX: why it does not update last_msg if msg_tail was the last message ?
} else {
msg_prev = msg_tail ;
msg_tail = msg_tail - > next ;
}
} else {
msg_prev = msg_tail ;
msg_tail = msg_tail - > next ;
}
}
}
2015-05-16 17:43:06 +00:00
int handle__connect ( struct mosquitto_db * db , struct mosquitto * context )
2014-05-07 22:27:00 +00:00
{
2018-05-02 17:08:40 +00:00
char protocol_name [ 7 ] ;
2014-05-07 22:27:00 +00:00
uint8_t protocol_version ;
uint8_t connect_flags ;
2014-05-31 14:20:40 +00:00
uint8_t connect_ack = 0 ;
2014-05-07 22:27:00 +00:00
char * client_id = NULL ;
char * will_payload = NULL , * will_topic = NULL ;
2016-02-11 21:17:55 +00:00
char * will_topic_mount ;
2014-05-07 22:27:00 +00:00
uint16_t will_payloadlen ;
2018-10-24 13:07:09 +00:00
struct mosquitto_message_all * will_struct = NULL ;
2018-11-27 10:02:10 +00:00
uint8_t will , will_retain , will_qos , clean_start ;
2014-05-07 22:27:00 +00:00
uint8_t username_flag , password_flag ;
char * username = NULL , * password = NULL ;
int rc ;
2015-04-19 21:10:59 +00:00
struct mosquitto__acl_user * acl_tail ;
2014-06-23 16:57:35 +00:00
struct mosquitto * found_context ;
2014-05-07 22:27:00 +00:00
int slen ;
2018-05-02 17:08:40 +00:00
uint16_t slen16 ;
2015-04-19 21:10:59 +00:00
struct mosquitto__subleaf * leaf ;
2014-09-14 17:12:30 +00:00
int i ;
2018-05-01 21:36:13 +00:00
struct mosquitto__security_options * security_opts ;
2018-11-01 23:50:54 +00:00
mosquitto_property * properties = NULL ;
2015-01-15 20:11:14 +00:00
# ifdef WITH_TLS
2014-06-30 04:33:41 +00:00
X509 * client_cert = NULL ;
2014-05-07 22:27:00 +00:00
X509_NAME * name ;
X509_NAME_ENTRY * name_entry ;
2018-06-27 15:04:49 +00:00
ASN1_STRING * name_asn1 = NULL ;
2014-05-07 22:27:00 +00:00
# endif
2015-05-16 11:25:35 +00:00
G_CONNECTION_COUNT_INC ( ) ;
2014-05-07 22:27:00 +00:00
2018-03-15 12:18:19 +00:00
if ( ! context - > listener ) {
return MOSQ_ERR_INVAL ;
}
2014-05-07 22:27:00 +00:00
/* Don't accept multiple CONNECT commands. */
if ( context - > state ! = mosq_cs_new ) {
2014-06-28 00:38:58 +00:00
rc = MOSQ_ERR_PROTOCOL ;
goto handle_connect_error ;
2014-05-07 22:27:00 +00:00
}
2018-05-02 17:08:40 +00:00
/* Read protocol name as length then bytes rather than with read_string
* because the length is fixed and we can check that . Removes the need
* for another malloc as well . */
if ( packet__read_uint16 ( & context - > in_packet , & slen16 ) ) {
2014-06-28 00:38:58 +00:00
rc = 1 ;
goto handle_connect_error ;
2014-05-07 22:27:00 +00:00
}
2018-05-02 17:08:40 +00:00
slen = slen16 ;
if ( slen ! = 4 /* MQTT */ & & slen ! = 6 /* MQIsdp */ ) {
rc = MOSQ_ERR_PROTOCOL ;
2014-06-28 00:38:58 +00:00
goto handle_connect_error ;
2014-05-07 22:27:00 +00:00
}
2018-05-02 17:08:40 +00:00
if ( packet__read_bytes ( & context - > in_packet , protocol_name , slen ) ) {
rc = MOSQ_ERR_PROTOCOL ;
goto handle_connect_error ;
}
protocol_name [ slen ] = ' \0 ' ;
2015-05-16 13:16:40 +00:00
if ( packet__read_byte ( & context - > in_packet , & protocol_version ) ) {
2014-06-28 00:38:58 +00:00
rc = 1 ;
goto handle_connect_error ;
2014-05-07 22:27:00 +00:00
}
if ( ! strcmp ( protocol_name , PROTOCOL_NAME_v31 ) ) {
if ( ( protocol_version & 0x7F ) ! = PROTOCOL_VERSION_v31 ) {
if ( db - > config - > connection_messages = = true ) {
2015-05-18 07:53:21 +00:00
log__printf ( NULL , MOSQ_LOG_INFO , " Invalid protocol version %d in CONNECT from %s. " ,
2014-05-07 22:27:00 +00:00
protocol_version , context - > address ) ;
}
2018-11-22 17:32:43 +00:00
send__connack ( db , context , 0 , CONNACK_REFUSED_PROTOCOL_VERSION ) ;
2014-06-28 00:38:58 +00:00
rc = MOSQ_ERR_PROTOCOL ;
goto handle_connect_error ;
2014-05-07 22:27:00 +00:00
}
context - > protocol = mosq_p_mqtt31 ;
2018-08-30 15:31:51 +00:00
} else if ( ! strcmp ( protocol_name , PROTOCOL_NAME ) ) {
2018-12-30 21:51:05 +00:00
if ( ( protocol_version & 0x7F ) = = PROTOCOL_VERSION_v311 ) {
context - > protocol = mosq_p_mqtt311 ;
} else if ( ( protocol_version & 0x7F ) = = PROTOCOL_VERSION_v5 ) {
context - > protocol = mosq_p_mqtt5 ;
} else {
2014-05-07 22:27:00 +00:00
if ( db - > config - > connection_messages = = true ) {
2015-05-18 07:53:21 +00:00
log__printf ( NULL , MOSQ_LOG_INFO , " Invalid protocol version %d in CONNECT from %s. " ,
2014-05-07 22:27:00 +00:00
protocol_version , context - > address ) ;
}
2018-11-22 17:32:43 +00:00
send__connack ( db , context , 0 , CONNACK_REFUSED_PROTOCOL_VERSION ) ;
2014-06-28 00:38:58 +00:00
rc = MOSQ_ERR_PROTOCOL ;
goto handle_connect_error ;
2014-05-07 22:27:00 +00:00
}
if ( ( context - > in_packet . command & 0x0F ) ! = 0x00 ) {
2016-03-06 22:30:17 +00:00
/* Reserved flags not set to 0, must disconnect. */
2014-06-28 00:38:58 +00:00
rc = MOSQ_ERR_PROTOCOL ;
goto handle_connect_error ;
2014-05-07 22:27:00 +00:00
}
} else {
if ( db - > config - > connection_messages = = true ) {
2015-05-18 07:53:21 +00:00
log__printf ( NULL , MOSQ_LOG_INFO , " Invalid protocol \" %s \" in CONNECT from %s. " ,
2014-05-07 22:27:00 +00:00
protocol_name , context - > address ) ;
}
2014-06-28 00:38:58 +00:00
rc = MOSQ_ERR_PROTOCOL ;
goto handle_connect_error ;
2014-05-07 22:27:00 +00:00
}
2015-05-16 13:16:40 +00:00
if ( packet__read_byte ( & context - > in_packet , & connect_flags ) ) {
2014-06-28 00:38:58 +00:00
rc = 1 ;
goto handle_connect_error ;
2014-05-07 22:27:00 +00:00
}
2018-12-30 21:51:05 +00:00
if ( context - > protocol = = mosq_p_mqtt311 | | context - > protocol = = mosq_p_mqtt5 ) {
2017-06-27 10:11:43 +00:00
if ( ( connect_flags & 0x01 ) ! = 0x00 ) {
rc = MOSQ_ERR_PROTOCOL ;
goto handle_connect_error ;
}
}
2018-11-27 10:02:10 +00:00
clean_start = ( connect_flags & 0x02 ) > > 1 ;
2014-05-07 22:27:00 +00:00
will = connect_flags & 0x04 ;
will_qos = ( connect_flags & 0x18 ) > > 3 ;
if ( will_qos = = 3 ) {
2015-05-18 07:53:21 +00:00
log__printf ( NULL , MOSQ_LOG_INFO , " Invalid Will QoS in CONNECT from %s. " ,
2014-05-07 22:27:00 +00:00
context - > address ) ;
2014-06-28 00:38:58 +00:00
rc = MOSQ_ERR_PROTOCOL ;
goto handle_connect_error ;
2014-05-07 22:27:00 +00:00
}
2016-07-22 09:37:30 +00:00
will_retain = ( ( connect_flags & 0x20 ) = = 0x20 ) ; // Temporary hack because MSVC<1800 doesn't have stdbool.h.
2014-05-07 22:27:00 +00:00
password_flag = connect_flags & 0x40 ;
username_flag = connect_flags & 0x80 ;
2018-11-22 18:15:02 +00:00
if ( will & & will_retain & & db - > config - > retain_available = = false ) {
if ( protocol_version = = mosq_p_mqtt5 ) {
send__connack ( db , context , 0 , MQTT_RC_RETAIN_NOT_SUPPORTED ) ;
}
rc = 1 ;
goto handle_connect_error ;
}
2015-05-16 13:16:40 +00:00
if ( packet__read_uint16 ( & context - > in_packet , & ( context - > keepalive ) ) ) {
2014-06-28 00:38:58 +00:00
rc = 1 ;
goto handle_connect_error ;
2014-05-07 22:27:00 +00:00
}
2018-12-30 21:51:05 +00:00
if ( protocol_version = = PROTOCOL_VERSION_v5 ) {
2018-10-30 11:00:16 +00:00
rc = property__read_all ( CMD_CONNECT , & context - > in_packet , & properties ) ;
2018-10-02 15:27:40 +00:00
if ( rc ) return rc ;
2018-10-30 10:11:20 +00:00
mosquitto_property_free_all ( & properties ) ;
2018-12-30 21:51:05 +00:00
}
2018-11-27 12:23:21 +00:00
property__process_connect ( context , properties ) ;
2018-10-30 10:11:20 +00:00
mosquitto_property_free_all ( & properties ) ; /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */
2018-12-30 21:51:05 +00:00
2018-02-11 20:47:17 +00:00
if ( packet__read_string ( & context - > in_packet , & client_id , & slen ) ) {
2014-06-28 00:38:58 +00:00
rc = 1 ;
goto handle_connect_error ;
2014-05-07 22:27:00 +00:00
}
if ( slen = = 0 ) {
if ( context - > protocol = = mosq_p_mqtt31 ) {
2018-11-22 17:32:43 +00:00
send__connack ( db , context , 0 , CONNACK_REFUSED_IDENTIFIER_REJECTED ) ;
2014-06-28 00:38:58 +00:00
rc = MOSQ_ERR_PROTOCOL ;
goto handle_connect_error ;
2018-12-30 21:51:05 +00:00
} else { /* mqtt311/mqtt5 */
2015-04-19 21:10:59 +00:00
mosquitto__free ( client_id ) ;
2014-10-21 22:11:31 +00:00
client_id = NULL ;
2014-05-07 22:27:00 +00:00
2018-03-18 21:23:50 +00:00
bool allow_zero_length_clientid ;
if ( db - > config - > per_listener_settings ) {
allow_zero_length_clientid = context - > listener - > security_options . allow_zero_length_clientid ;
} else {
allow_zero_length_clientid = db - > config - > security_options . allow_zero_length_clientid ;
}
2018-11-27 10:02:10 +00:00
if ( clean_start = = 0 | | allow_zero_length_clientid = = false ) {
2018-11-22 17:32:43 +00:00
send__connack ( db , context , 0 , CONNACK_REFUSED_IDENTIFIER_REJECTED ) ;
2014-06-28 00:38:58 +00:00
rc = MOSQ_ERR_PROTOCOL ;
goto handle_connect_error ;
2014-05-31 21:12:20 +00:00
} else {
2018-03-18 21:07:04 +00:00
if ( db - > config - > per_listener_settings ) {
client_id = client_id_gen ( db , & slen , context - > listener - > security_options . auto_id_prefix , context - > listener - > security_options . auto_id_prefix_len ) ;
} else {
client_id = client_id_gen ( db , & slen , db - > config - > security_options . auto_id_prefix , db - > config - > security_options . auto_id_prefix_len ) ;
}
2014-05-07 22:27:00 +00:00
if ( ! client_id ) {
2014-06-28 00:38:58 +00:00
rc = MOSQ_ERR_NOMEM ;
goto handle_connect_error ;
2014-05-07 22:27:00 +00:00
}
}
}
}
/* clientid_prefixes check */
if ( db - > config - > clientid_prefixes ) {
if ( strncmp ( db - > config - > clientid_prefixes , client_id , strlen ( db - > config - > clientid_prefixes ) ) ) {
2018-11-22 17:32:43 +00:00
send__connack ( db , context , 0 , CONNACK_REFUSED_NOT_AUTHORIZED ) ;
2014-10-12 22:58:49 +00:00
rc = 1 ;
2014-06-28 00:38:58 +00:00
goto handle_connect_error ;
2014-05-07 22:27:00 +00:00
}
}
if ( will ) {
2018-10-24 13:07:09 +00:00
will_struct = mosquitto__calloc ( 1 , sizeof ( struct mosquitto_message_all ) ) ;
2014-05-07 22:27:00 +00:00
if ( ! will_struct ) {
rc = MOSQ_ERR_NOMEM ;
goto handle_connect_error ;
}
2018-10-10 07:41:10 +00:00
if ( protocol_version = = PROTOCOL_VERSION_v5 ) {
2018-10-25 10:23:04 +00:00
rc = property__read_all ( CMD_WILL , & context - > in_packet , & will_struct - > properties ) ;
2018-10-10 07:41:10 +00:00
if ( rc ) return rc ;
2018-10-30 10:11:20 +00:00
mosquitto_property_free_all ( & properties ) ; /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */
2018-10-10 07:41:10 +00:00
}
2018-02-11 20:47:17 +00:00
if ( packet__read_string ( & context - > in_packet , & will_topic , & slen ) ) {
2014-05-07 22:27:00 +00:00
rc = 1 ;
goto handle_connect_error ;
}
2018-02-11 20:47:17 +00:00
if ( ! slen ) {
2014-05-07 22:27:00 +00:00
rc = 1 ;
goto handle_connect_error ;
}
2016-02-11 21:17:55 +00:00
2018-03-15 12:18:19 +00:00
if ( context - > listener - > mount_point ) {
2016-03-05 22:38:05 +00:00
slen = strlen ( context - > listener - > mount_point ) + strlen ( will_topic ) + 1 ;
2016-06-21 22:33:58 +00:00
will_topic_mount = mosquitto__malloc ( slen + 1 ) ;
2016-02-11 21:17:55 +00:00
if ( ! will_topic_mount ) {
rc = MOSQ_ERR_NOMEM ;
goto handle_connect_error ;
}
snprintf ( will_topic_mount , slen , " %s%s " , context - > listener - > mount_point , will_topic ) ;
will_topic_mount [ slen ] = ' \0 ' ;
2016-06-21 22:33:58 +00:00
mosquitto__free ( will_topic ) ;
2016-02-11 21:17:55 +00:00
will_topic = will_topic_mount ;
}
2014-09-10 14:57:20 +00:00
if ( mosquitto_pub_topic_check ( will_topic ) ) {
2014-05-07 22:27:00 +00:00
rc = 1 ;
goto handle_connect_error ;
}
2015-05-16 13:16:40 +00:00
if ( packet__read_uint16 ( & context - > in_packet , & will_payloadlen ) ) {
2014-05-07 22:27:00 +00:00
rc = 1 ;
goto handle_connect_error ;
}
if ( will_payloadlen > 0 ) {
2015-04-19 21:10:59 +00:00
will_payload = mosquitto__malloc ( will_payloadlen ) ;
2014-05-07 22:27:00 +00:00
if ( ! will_payload ) {
rc = 1 ;
goto handle_connect_error ;
}
2015-05-16 13:16:40 +00:00
rc = packet__read_bytes ( & context - > in_packet , will_payload , will_payloadlen ) ;
2014-05-07 22:27:00 +00:00
if ( rc ) {
rc = 1 ;
goto handle_connect_error ;
}
}
} else {
2018-12-30 21:51:05 +00:00
if ( context - > protocol = = mosq_p_mqtt311 | | context - > protocol = = mosq_p_mqtt5 ) {
2014-05-07 22:27:00 +00:00
if ( will_qos ! = 0 | | will_retain ! = 0 ) {
rc = MOSQ_ERR_PROTOCOL ;
goto handle_connect_error ;
}
}
}
if ( username_flag ) {
2018-02-11 20:47:17 +00:00
rc = packet__read_string ( & context - > in_packet , & username , & slen ) ;
2014-05-07 22:27:00 +00:00
if ( rc = = MOSQ_ERR_SUCCESS ) {
if ( password_flag ) {
2018-10-03 14:04:24 +00:00
/* FIXME - MQTT 5 this is binary data */
2018-02-11 20:47:17 +00:00
rc = packet__read_string ( & context - > in_packet , & password , & slen ) ;
2014-05-07 22:27:00 +00:00
if ( rc = = MOSQ_ERR_NOMEM ) {
rc = MOSQ_ERR_NOMEM ;
goto handle_connect_error ;
} else if ( rc = = MOSQ_ERR_PROTOCOL ) {
if ( context - > protocol = = mosq_p_mqtt31 ) {
/* Password flag given, but no password. Ignore. */
password_flag = 0 ;
2018-12-30 21:51:05 +00:00
} else {
2014-05-07 22:27:00 +00:00
rc = MOSQ_ERR_PROTOCOL ;
goto handle_connect_error ;
}
}
}
} else if ( rc = = MOSQ_ERR_NOMEM ) {
rc = MOSQ_ERR_NOMEM ;
goto handle_connect_error ;
} else {
if ( context - > protocol = = mosq_p_mqtt31 ) {
/* Username flag given, but no username. Ignore. */
username_flag = 0 ;
2018-12-30 21:51:05 +00:00
} else {
2014-05-07 22:27:00 +00:00
rc = MOSQ_ERR_PROTOCOL ;
goto handle_connect_error ;
}
}
} else {
2018-12-30 21:51:05 +00:00
if ( context - > protocol = = mosq_p_mqtt311 | | context - > protocol = = mosq_p_mqtt5 ) {
2014-05-07 22:27:00 +00:00
if ( password_flag ) {
/* username_flag == 0 && password_flag == 1 is forbidden */
rc = MOSQ_ERR_PROTOCOL ;
goto handle_connect_error ;
}
}
}
2018-04-12 21:53:49 +00:00
if ( context - > in_packet . pos ! = context - > in_packet . remaining_length ) {
/* Surplus data at end of packet, this must be an error. */
rc = MOSQ_ERR_PROTOCOL ;
goto handle_connect_error ;
}
2014-05-07 22:27:00 +00:00
# ifdef WITH_TLS
2015-06-05 11:33:07 +00:00
if ( context - > listener & & context - > listener - > ssl_ctx & & ( context - > listener - > use_identity_as_username | | context - > listener - > use_subject_as_username ) ) {
2017-07-26 22:25:49 +00:00
/* Don't need the username or password if provided */
2018-02-13 14:16:47 +00:00
mosquitto__free ( username ) ;
2017-07-26 22:25:49 +00:00
username = NULL ;
2018-02-13 14:16:47 +00:00
mosquitto__free ( password ) ;
2017-07-26 22:25:49 +00:00
password = NULL ;
2014-05-07 22:27:00 +00:00
if ( ! context - > ssl ) {
2018-11-22 17:32:43 +00:00
send__connack ( db , context , 0 , CONNACK_REFUSED_BAD_USERNAME_PASSWORD ) ;
2014-10-12 22:58:49 +00:00
rc = 1 ;
2014-05-07 22:27:00 +00:00
goto handle_connect_error ;
}
2018-04-11 16:10:27 +00:00
# ifdef WITH_TLS_PSK
2014-05-07 22:27:00 +00:00
if ( context - > listener - > psk_hint ) {
/* Client should have provided an identity to get this far. */
if ( ! context - > username ) {
2018-11-22 17:32:43 +00:00
send__connack ( db , context , 0 , CONNACK_REFUSED_BAD_USERNAME_PASSWORD ) ;
2014-10-12 22:58:49 +00:00
rc = 1 ;
2014-05-07 22:27:00 +00:00
goto handle_connect_error ;
}
} else {
2018-04-11 16:10:27 +00:00
# endif /* WITH_TLS_PSK */
2014-05-07 22:27:00 +00:00
client_cert = SSL_get_peer_certificate ( context - > ssl ) ;
if ( ! client_cert ) {
2018-11-22 17:32:43 +00:00
send__connack ( db , context , 0 , CONNACK_REFUSED_BAD_USERNAME_PASSWORD ) ;
2014-10-12 22:58:49 +00:00
rc = 1 ;
2014-05-07 22:27:00 +00:00
goto handle_connect_error ;
}
name = X509_get_subject_name ( client_cert ) ;
if ( ! name ) {
2018-11-22 17:32:43 +00:00
send__connack ( db , context , 0 , CONNACK_REFUSED_BAD_USERNAME_PASSWORD ) ;
2014-10-12 22:58:49 +00:00
rc = 1 ;
2014-05-07 22:27:00 +00:00
goto handle_connect_error ;
}
2015-06-05 11:33:07 +00:00
if ( context - > listener - > use_identity_as_username ) { //use_identity_as_username
i = X509_NAME_get_index_by_NID ( name , NID_commonName , - 1 ) ;
if ( i = = - 1 ) {
2018-11-22 17:32:43 +00:00
send__connack ( db , context , 0 , CONNACK_REFUSED_BAD_USERNAME_PASSWORD ) ;
2015-06-05 11:33:07 +00:00
rc = 1 ;
goto handle_connect_error ;
}
name_entry = X509_NAME_get_entry ( name , i ) ;
2015-06-12 21:52:15 +00:00
if ( name_entry ) {
2018-06-27 15:04:49 +00:00
name_asn1 = X509_NAME_ENTRY_get_data ( name_entry ) ;
if ( name_asn1 = = NULL ) {
2018-11-22 17:32:43 +00:00
send__connack ( db , context , 0 , CONNACK_REFUSED_BAD_USERNAME_PASSWORD ) ;
2018-06-27 15:04:49 +00:00
rc = 1 ;
goto handle_connect_error ;
}
context - > username = mosquitto__strdup ( ( char * ) ASN1_STRING_data ( name_asn1 ) ) ;
2018-08-08 14:35:42 +00:00
if ( ! context - > username ) {
2018-11-22 17:32:43 +00:00
send__connack ( db , context , 0 , CONNACK_REFUSED_SERVER_UNAVAILABLE ) ;
2018-08-08 14:35:42 +00:00
rc = MOSQ_ERR_NOMEM ;
goto handle_connect_error ;
}
2018-06-27 15:04:49 +00:00
/* Make sure there isn't an embedded NUL character in the CN */
if ( ( size_t ) ASN1_STRING_length ( name_asn1 ) ! = strlen ( context - > username ) ) {
2018-11-22 17:32:43 +00:00
send__connack ( db , context , 0 , CONNACK_REFUSED_BAD_USERNAME_PASSWORD ) ;
2018-06-27 15:04:49 +00:00
rc = 1 ;
goto handle_connect_error ;
}
2015-06-12 21:52:15 +00:00
}
2015-06-05 11:33:07 +00:00
} else { // use_subject_as_username
2015-06-12 21:52:15 +00:00
BIO * subject_bio = BIO_new ( BIO_s_mem ( ) ) ;
X509_NAME_print_ex ( subject_bio , X509_get_subject_name ( client_cert ) , 0 , XN_FLAG_RFC2253 ) ;
char * data_start = NULL ;
long name_length = BIO_get_mem_data ( subject_bio , & data_start ) ;
char * subject = mosquitto__malloc ( sizeof ( char ) * name_length + 1 ) ;
if ( ! subject ) {
BIO_free ( subject_bio ) ;
rc = MOSQ_ERR_NOMEM ;
goto handle_connect_error ;
}
memcpy ( subject , data_start , name_length ) ;
subject [ name_length ] = ' \0 ' ;
BIO_free ( subject_bio ) ;
2015-06-05 11:33:07 +00:00
context - > username = subject ;
2014-05-07 22:27:00 +00:00
}
if ( ! context - > username ) {
2014-10-12 22:58:49 +00:00
rc = 1 ;
2014-05-07 22:27:00 +00:00
goto handle_connect_error ;
}
2014-06-30 04:33:41 +00:00
X509_free ( client_cert ) ;
client_cert = NULL ;
2018-04-11 16:10:27 +00:00
# ifdef WITH_TLS_PSK
2014-05-07 22:27:00 +00:00
}
2018-04-11 16:10:27 +00:00
# endif /* WITH_TLS_PSK */
2014-05-07 22:27:00 +00:00
} else {
# endif /* WITH_TLS */
if ( username_flag ) {
2018-08-16 16:00:00 +00:00
/* FIXME - these ensure the mosquitto_client_id() and
* mosquitto_client_username ( ) functions work , but is hacky */
context - > id = client_id ;
context - > username = username ;
2016-07-08 12:27:14 +00:00
rc = mosquitto_unpwd_check ( db , context , username , password ) ;
2018-08-16 16:00:00 +00:00
context - > username = NULL ;
context - > id = NULL ;
2014-07-13 20:20:18 +00:00
switch ( rc ) {
case MOSQ_ERR_SUCCESS :
break ;
case MOSQ_ERR_AUTH :
2018-11-22 17:32:43 +00:00
send__connack ( db , context , 0 , CONNACK_REFUSED_NOT_AUTHORIZED ) ;
2015-05-16 14:24:24 +00:00
context__disconnect ( db , context ) ;
2014-10-12 22:58:49 +00:00
rc = 1 ;
2014-07-13 20:20:18 +00:00
goto handle_connect_error ;
break ;
default :
2015-05-16 14:24:24 +00:00
context__disconnect ( db , context ) ;
2014-10-12 22:58:49 +00:00
rc = 1 ;
2014-07-13 20:20:18 +00:00
goto handle_connect_error ;
break ;
2014-05-07 22:27:00 +00:00
}
context - > username = username ;
context - > password = password ;
username = NULL ; /* Avoid free() in error: below. */
password = NULL ;
}
2018-03-15 12:18:19 +00:00
if ( ! username_flag ) {
if ( ( db - > config - > per_listener_settings & & context - > listener - > security_options . allow_anonymous = = false )
| | ( ! db - > config - > per_listener_settings & & db - > config - > security_options . allow_anonymous = = false ) ) {
2018-11-22 17:32:43 +00:00
send__connack ( db , context , 0 , CONNACK_REFUSED_NOT_AUTHORIZED ) ;
2018-03-15 12:18:19 +00:00
rc = 1 ;
goto handle_connect_error ;
}
2014-05-07 22:27:00 +00:00
}
# ifdef WITH_TLS
}
# endif
2014-07-01 23:09:50 +00:00
if ( context - > listener & & context - > listener - > use_username_as_clientid ) {
if ( context - > username ) {
2015-04-19 21:10:59 +00:00
mosquitto__free ( client_id ) ;
client_id = mosquitto__strdup ( context - > username ) ;
2014-07-01 23:09:50 +00:00
if ( ! client_id ) {
rc = MOSQ_ERR_NOMEM ;
goto handle_connect_error ;
}
} else {
2018-11-22 17:32:43 +00:00
send__connack ( db , context , 0 , CONNACK_REFUSED_NOT_AUTHORIZED ) ;
2014-10-12 22:58:49 +00:00
rc = 1 ;
2014-07-01 23:09:50 +00:00
goto handle_connect_error ;
}
}
2014-05-07 22:27:00 +00:00
/* Find if this client already has an entry. This must be done *after* any security checks. */
2014-06-23 16:57:35 +00:00
HASH_FIND ( hh_id , db - > contexts_by_id , client_id , strlen ( client_id ) , found_context ) ;
if ( found_context ) {
2014-05-07 22:27:00 +00:00
/* Found a matching client */
2014-06-30 05:58:56 +00:00
if ( found_context - > sock = = INVALID_SOCKET ) {
2014-05-07 22:27:00 +00:00
/* Client is reconnecting after a disconnect */
2014-09-16 23:03:14 +00:00
/* FIXME - does anything need to be done here? */
2014-05-07 22:27:00 +00:00
} else {
2014-06-30 22:30:43 +00:00
/* Client is already connected, disconnect old version. This is
2015-05-16 14:24:24 +00:00
* done in context__cleanup ( ) below . */
2014-05-07 22:27:00 +00:00
if ( db - > config - > connection_messages = = true ) {
2015-05-18 07:53:21 +00:00
log__printf ( NULL , MOSQ_LOG_ERR , " Client %s already connected, closing old connection. " , client_id ) ;
2014-05-07 22:27:00 +00:00
}
}
2014-06-30 05:58:56 +00:00
2018-12-30 21:51:05 +00:00
if ( context - > protocol = = mosq_p_mqtt311 | | context - > protocol = = mosq_p_mqtt5 ) {
2018-11-27 10:02:10 +00:00
if ( clean_start = = 0 ) {
2014-05-31 14:20:40 +00:00
connect_ack | = 0x01 ;
}
}
2014-06-30 05:58:56 +00:00
2018-11-27 10:02:10 +00:00
context - > clean_start = clean_start ;
2014-06-30 22:30:43 +00:00
2018-11-27 10:02:10 +00:00
if ( context - > clean_start = = false & & found_context - > clean_start = = false ) {
2016-04-18 13:41:47 +00:00
if ( found_context - > inflight_msgs | | found_context - > queued_msgs ) {
context - > inflight_msgs = found_context - > inflight_msgs ;
context - > queued_msgs = found_context - > queued_msgs ;
found_context - > inflight_msgs = NULL ;
found_context - > queued_msgs = NULL ;
2015-05-16 14:24:24 +00:00
db__message_reconnect_reset ( db , context ) ;
2014-10-12 22:58:49 +00:00
}
2014-10-16 22:48:56 +00:00
context - > subs = found_context - > subs ;
found_context - > subs = NULL ;
context - > sub_count = found_context - > sub_count ;
found_context - > sub_count = 0 ;
2016-03-05 22:34:05 +00:00
context - > last_mid = found_context - > last_mid ;
2014-10-16 22:48:56 +00:00
for ( i = 0 ; i < context - > sub_count ; i + + ) {
2014-10-20 17:01:45 +00:00
if ( context - > subs [ i ] ) {
leaf = context - > subs [ i ] - > subs ;
while ( leaf ) {
if ( leaf - > context = = found_context ) {
leaf - > context = context ;
}
leaf = leaf - > next ;
2014-10-16 22:48:56 +00:00
}
2014-10-12 10:38:21 +00:00
}
}
}
2014-10-16 22:48:56 +00:00
2018-11-27 10:02:10 +00:00
found_context - > clean_start = true ;
2018-08-15 16:27:59 +00:00
found_context - > state = mosq_cs_duplicate ;
2014-10-16 22:48:56 +00:00
do_disconnect ( db , found_context ) ;
2014-05-07 22:27:00 +00:00
}
/* Associate user with its ACL, assuming we have ACLs loaded. */
2018-05-01 21:36:13 +00:00
if ( db - > config - > per_listener_settings ) {
if ( ! context - > listener ) {
return 1 ;
}
security_opts = & context - > listener - > security_options ;
} else {
security_opts = & db - > config - > security_options ;
}
if ( security_opts - > acl_list ) {
acl_tail = security_opts - > acl_list ;
2014-05-07 22:27:00 +00:00
while ( acl_tail ) {
if ( context - > username ) {
if ( acl_tail - > username & & ! strcmp ( context - > username , acl_tail - > username ) ) {
context - > acl_list = acl_tail ;
break ;
}
} else {
if ( acl_tail - > username = = NULL ) {
context - > acl_list = acl_tail ;
break ;
}
}
acl_tail = acl_tail - > next ;
}
} else {
context - > acl_list = NULL ;
}
2018-05-01 21:36:13 +00:00
2014-05-07 22:27:00 +00:00
if ( will_struct ) {
context - > will = will_struct ;
2018-10-24 13:07:09 +00:00
context - > will - > msg . topic = will_topic ;
2014-05-07 22:27:00 +00:00
if ( will_payload ) {
2018-10-24 13:07:09 +00:00
context - > will - > msg . payload = will_payload ;
context - > will - > msg . payloadlen = will_payloadlen ;
2014-05-07 22:27:00 +00:00
} else {
2018-10-24 13:07:09 +00:00
context - > will - > msg . payload = NULL ;
context - > will - > msg . payloadlen = 0 ;
2014-05-07 22:27:00 +00:00
}
2018-10-24 13:07:09 +00:00
context - > will - > msg . qos = will_qos ;
context - > will - > msg . retain = will_retain ;
2014-05-07 22:27:00 +00:00
}
if ( db - > config - > connection_messages = = true ) {
if ( context - > is_bridge ) {
if ( context - > username ) {
2018-11-27 10:02:10 +00:00
log__printf ( NULL , MOSQ_LOG_NOTICE , " New bridge connected from %s as %s (c%d, k%d, u'%s'). " , context - > address , client_id , clean_start , context - > keepalive , context - > username ) ;
2014-05-07 22:27:00 +00:00
} else {
2018-11-27 10:02:10 +00:00
log__printf ( NULL , MOSQ_LOG_NOTICE , " New bridge connected from %s as %s (c%d, k%d). " , context - > address , client_id , clean_start , context - > keepalive ) ;
2014-05-07 22:27:00 +00:00
}
} else {
if ( context - > username ) {
2018-11-27 10:02:10 +00:00
log__printf ( NULL , MOSQ_LOG_NOTICE , " New client connected from %s as %s (c%d, k%d, u'%s'). " , context - > address , client_id , clean_start , context - > keepalive , context - > username ) ;
2014-05-07 22:27:00 +00:00
} else {
2018-11-27 10:02:10 +00:00
log__printf ( NULL , MOSQ_LOG_NOTICE , " New client connected from %s as %s (p%d, c%d, k%d). " , context - > address , client_id , context - > protocol , clean_start , context - > keepalive ) ;
2014-05-07 22:27:00 +00:00
}
}
2018-01-30 13:36:58 +00:00
if ( context - > will ) {
2018-10-24 13:07:09 +00:00
log__printf ( NULL , MOSQ_LOG_DEBUG , " Will message specified (%ld bytes) (r%d, q%d). " ,
( long ) context - > will - > msg . payloadlen ,
context - > will - > msg . retain ,
context - > will - > msg . qos ) ;
log__printf ( NULL , MOSQ_LOG_DEBUG , " \t %s " , context - > will - > msg . topic ) ;
2018-01-30 13:36:58 +00:00
} else {
log__printf ( NULL , MOSQ_LOG_DEBUG , " No will message specified. " ) ;
}
2014-05-07 22:27:00 +00:00
}
2014-06-02 21:08:40 +00:00
context - > id = client_id ;
client_id = NULL ;
2018-11-27 10:02:10 +00:00
context - > clean_start = clean_start ;
2014-06-02 21:08:40 +00:00
context - > ping_t = 0 ;
context - > is_dropping = false ;
if ( ( protocol_version & 0x80 ) = = 0x80 ) {
context - > is_bridge = true ;
}
2016-04-18 15:48:11 +00:00
connection_check_acl ( db , context , & context - > inflight_msgs ) ;
connection_check_acl ( db , context , & context - > queued_msgs ) ;
2014-06-13 22:07:00 +00:00
2014-06-23 16:57:35 +00:00
HASH_ADD_KEYPTR ( hh_id , db - > contexts_by_id , context - > id , strlen ( context - > id ) , context ) ;
2014-06-02 21:08:40 +00:00
# ifdef WITH_PERSISTENCE
2018-11-27 10:02:10 +00:00
if ( ! clean_start ) {
2014-06-02 21:08:40 +00:00
db - > persistence_changes + + ;
}
# endif
2014-05-07 22:27:00 +00:00
context - > state = mosq_cs_connected ;
2018-11-22 17:32:43 +00:00
return send__connack ( db , context , connect_ack , CONNACK_ACCEPTED ) ;
2014-05-07 22:27:00 +00:00
handle_connect_error :
2015-08-18 13:53:22 +00:00
mosquitto__free ( client_id ) ;
mosquitto__free ( username ) ;
mosquitto__free ( password ) ;
mosquitto__free ( will_payload ) ;
mosquitto__free ( will_topic ) ;
2018-10-25 09:24:19 +00:00
if ( will_struct ) {
2018-10-30 10:11:20 +00:00
mosquitto_property_free_all ( & will_struct - > properties ) ;
2018-10-25 09:24:19 +00:00
}
2015-08-18 13:53:22 +00:00
mosquitto__free ( will_struct ) ;
2014-06-30 04:33:41 +00:00
# ifdef WITH_TLS
if ( client_cert ) X509_free ( client_cert ) ;
# endif
2014-07-03 16:37:31 +00:00
/* We return an error here which means the client is freed later on. */
2014-05-07 22:27:00 +00:00
return rc ;
}
2018-11-27 12:23:21 +00:00
2015-05-16 17:43:06 +00:00
int handle__disconnect ( struct mosquitto_db * db , struct mosquitto * context )
2014-05-07 22:27:00 +00:00
{
2018-10-25 11:03:22 +00:00
int rc ;
2018-11-27 12:23:21 +00:00
uint8_t reason_code ;
2018-11-01 23:50:54 +00:00
mosquitto_property * properties = NULL ;
2018-10-25 11:03:22 +00:00
2014-05-07 22:27:00 +00:00
if ( ! context ) {
return MOSQ_ERR_INVAL ;
}
2018-10-25 11:03:22 +00:00
if ( context - > protocol = = mosq_p_mqtt5 ) {
2018-11-27 12:23:21 +00:00
/* FIXME - must handle reason code */
rc = packet__read_byte ( & context - > in_packet , & reason_code ) ;
if ( rc ) return rc ;
2018-10-30 11:00:16 +00:00
rc = property__read_all ( CMD_DISCONNECT , & context - > in_packet , & properties ) ;
2018-10-25 11:03:22 +00:00
if ( rc ) return rc ;
2018-11-27 12:23:21 +00:00
}
rc = property__process_disconnect ( context , properties ) ;
if ( rc ) {
if ( rc = = MOSQ_ERR_PROTOCOL ) {
send__disconnect ( context , MQTT_RC_PROTOCOL_ERROR , NULL ) ;
}
2018-10-30 10:11:20 +00:00
mosquitto_property_free_all ( & properties ) ;
2018-11-27 12:23:21 +00:00
return rc ;
2018-10-25 11:03:22 +00:00
}
2018-10-30 10:11:20 +00:00
mosquitto_property_free_all ( & properties ) ; /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */
2018-10-25 11:03:22 +00:00
2014-05-07 22:27:00 +00:00
if ( context - > in_packet . remaining_length ! = 0 ) {
return MOSQ_ERR_PROTOCOL ;
}
2015-05-18 07:53:21 +00:00
log__printf ( NULL , MOSQ_LOG_DEBUG , " Received DISCONNECT from %s " , context - > id ) ;
2018-12-30 21:51:05 +00:00
if ( context - > protocol = = mosq_p_mqtt311 | | context - > protocol = = mosq_p_mqtt5 ) {
2014-05-07 22:27:00 +00:00
if ( ( context - > in_packet . command & 0x0F ) ! = 0x00 ) {
2014-07-08 22:07:19 +00:00
do_disconnect ( db , context ) ;
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_PROTOCOL ;
}
}
context - > state = mosq_cs_disconnecting ;
2014-07-03 00:00:57 +00:00
do_disconnect ( db , context ) ;
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_SUCCESS ;
}