2014-05-07 22:27:00 +00:00
/*
2015-04-19 21:10:59 +00:00
Copyright ( c ) 2009 - 2015 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 .
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.
Contributors :
Roger Light - initial implementation and documentation .
*/
# include <stdio.h>
# include <string.h>
2015-05-16 11:25:35 +00:00
# include "config.h"
2015-04-29 20:37:47 +00:00
# include "mosquitto_broker.h"
# include "mqtt3_protocol.h"
# include "memory_mosq.h"
# include "packet_mosq.h"
# 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
# include <libwebsockets.h>
# endif
2014-06-14 23:37:30 +00:00
static char * client_id_gen ( struct mosquitto_db * db )
{
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
2015-04-19 21:10:59 +00:00
client_id = ( char * ) mosquitto__calloc ( 37 + db - > config - > auto_id_prefix_len , sizeof ( char ) ) ;
2014-06-15 00:07:05 +00:00
if ( ! client_id ) {
return NULL ;
}
if ( db - > config - > auto_id_prefix ) {
memcpy ( client_id , db - > config - > auto_id_prefix , db - > config - > auto_id_prefix_len ) ;
}
uuid_generate_random ( uuid ) ;
uuid_unparse_lower ( uuid , & client_id [ db - > config - > auto_id_prefix_len ] ) ;
# else
2015-04-19 21:10:59 +00:00
client_id = ( char * ) mosquitto__calloc ( 65 + db - > config - > auto_id_prefix_len , sizeof ( char ) ) ;
2014-06-14 23:37:30 +00:00
if ( ! client_id ) {
return NULL ;
}
2014-06-15 00:07:05 +00:00
if ( db - > config - > auto_id_prefix ) {
memcpy ( client_id , db - > config - > auto_id_prefix , db - > config - > auto_id_prefix_len ) ;
}
2014-06-14 23:37:30 +00:00
for ( i = 0 ; i < 64 ; i + + ) {
client_id [ i + db - > config - > auto_id_prefix_len ] = ( rand ( ) % 73 ) + 48 ;
}
client_id [ i ] = ' \0 ' ;
2014-06-15 00:07:05 +00:00
# endif
2014-06-14 23:37:30 +00:00
return client_id ;
}
2014-05-07 22:27:00 +00:00
int mqtt3_handle_connect ( struct mosquitto_db * db , struct mosquitto * context )
{
char * protocol_name = NULL ;
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 ;
uint16_t will_payloadlen ;
struct mosquitto_message * will_struct = NULL ;
uint8_t will , will_retain , will_qos , clean_session ;
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-13 22:07:00 +00:00
struct mosquitto_client_msg * msg_tail , * msg_prev ;
2014-06-23 16:57:35 +00:00
struct mosquitto * found_context ;
2014-05-07 22:27:00 +00:00
int slen ;
2015-04-19 21:10:59 +00:00
struct mosquitto__subleaf * leaf ;
2014-09-14 17:12:30 +00:00
int i ;
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 ;
# endif
2015-05-16 11:25:35 +00:00
G_CONNECTION_COUNT_INC ( ) ;
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
}
2015-04-19 21:10:59 +00:00
if ( mosquitto__read_string ( & context - > in_packet , & protocol_name ) ) {
2014-06-28 00:38:58 +00:00
rc = 1 ;
goto handle_connect_error ;
2014-05-07 22:27:00 +00:00
return 1 ;
}
if ( ! protocol_name ) {
2014-06-28 00:38:58 +00:00
rc = 3 ;
goto handle_connect_error ;
2014-05-07 22:27:00 +00:00
return 3 ;
}
2015-04-19 21:10:59 +00:00
if ( mosquitto__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
return 1 ;
}
if ( ! strcmp ( protocol_name , PROTOCOL_NAME_v31 ) ) {
if ( ( protocol_version & 0x7F ) ! = PROTOCOL_VERSION_v31 ) {
if ( db - > config - > connection_messages = = true ) {
2015-04-19 21:10:59 +00:00
mosquitto__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 ) ;
}
2015-04-19 21:10:59 +00:00
mosquitto__send_connack ( context , 0 , CONNACK_REFUSED_PROTOCOL_VERSION ) ;
mosquitto__free ( protocol_name ) ;
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 ;
} else if ( ! strcmp ( protocol_name , PROTOCOL_NAME_v311 ) ) {
if ( ( protocol_version & 0x7F ) ! = PROTOCOL_VERSION_v311 ) {
if ( db - > config - > connection_messages = = true ) {
2015-04-19 21:10:59 +00:00
mosquitto__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 ) ;
}
2015-04-19 21:10:59 +00:00
mosquitto__send_connack ( context , 0 , CONNACK_REFUSED_PROTOCOL_VERSION ) ;
mosquitto__free ( protocol_name ) ;
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 ) {
/* Reserved flags not set to 0, must disconnect. */
2015-04-19 21:10:59 +00:00
mosquitto__free ( protocol_name ) ;
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_mqtt311 ;
} else {
if ( db - > config - > connection_messages = = true ) {
2015-04-19 21:10:59 +00:00
mosquitto__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 ) ;
}
2015-04-19 21:10:59 +00:00
mosquitto__free ( protocol_name ) ;
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-04-19 21:10:59 +00:00
mosquitto__free ( protocol_name ) ;
2014-05-07 22:27:00 +00:00
2015-04-19 21:10:59 +00:00
if ( mosquitto__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
}
2014-06-03 14:16:27 +00:00
clean_session = ( 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-04-19 21:10:59 +00:00
mosquitto__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
}
will_retain = connect_flags & 0x20 ;
password_flag = connect_flags & 0x40 ;
username_flag = connect_flags & 0x80 ;
2015-04-19 21:10:59 +00:00
if ( mosquitto__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
}
2015-04-19 21:10:59 +00:00
if ( mosquitto__read_string ( & context - > in_packet , & client_id ) ) {
2014-06-28 00:38:58 +00:00
rc = 1 ;
goto handle_connect_error ;
2014-05-07 22:27:00 +00:00
}
slen = strlen ( client_id ) ;
if ( slen = = 0 ) {
if ( context - > protocol = = mosq_p_mqtt31 ) {
2015-04-19 21:10:59 +00:00
mosquitto__send_connack ( context , 0 , CONNACK_REFUSED_IDENTIFIER_REJECTED ) ;
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 { /* mqtt311 */
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
2014-05-31 21:12:20 +00:00
if ( clean_session = = 0 | | db - > config - > allow_zero_length_clientid = = false ) {
2015-04-19 21:10:59 +00:00
mosquitto__send_connack ( 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 {
2014-06-14 23:37:30 +00:00
client_id = client_id_gen ( db ) ;
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 ) ) ) {
2015-04-19 21:10:59 +00:00
mosquitto__send_connack ( 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 ) {
2015-04-19 21:10:59 +00:00
will_struct = mosquitto__calloc ( 1 , sizeof ( struct mosquitto_message ) ) ;
2014-05-07 22:27:00 +00:00
if ( ! will_struct ) {
rc = MOSQ_ERR_NOMEM ;
goto handle_connect_error ;
}
2015-04-19 21:10:59 +00:00
if ( mosquitto__read_string ( & context - > in_packet , & will_topic ) ) {
2014-05-07 22:27:00 +00:00
rc = 1 ;
goto handle_connect_error ;
}
if ( strlen ( will_topic ) = = 0 ) {
rc = 1 ;
goto handle_connect_error ;
}
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-04-19 21:10:59 +00:00
if ( mosquitto__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-04-19 21:10:59 +00:00
rc = mosquitto__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 {
if ( context - > protocol = = mosq_p_mqtt311 ) {
if ( will_qos ! = 0 | | will_retain ! = 0 ) {
rc = MOSQ_ERR_PROTOCOL ;
goto handle_connect_error ;
}
}
}
if ( username_flag ) {
2015-04-19 21:10:59 +00:00
rc = mosquitto__read_string ( & context - > in_packet , & username ) ;
2014-05-07 22:27:00 +00:00
if ( rc = = MOSQ_ERR_SUCCESS ) {
if ( password_flag ) {
2015-04-19 21:10:59 +00:00
rc = mosquitto__read_string ( & context - > in_packet , & password ) ;
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 ;
} else if ( context - > protocol = = mosq_p_mqtt311 ) {
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 ;
} else if ( context - > protocol = = mosq_p_mqtt311 ) {
rc = MOSQ_ERR_PROTOCOL ;
goto handle_connect_error ;
}
}
} else {
if ( context - > protocol = = mosq_p_mqtt311 ) {
if ( password_flag ) {
/* username_flag == 0 && password_flag == 1 is forbidden */
rc = MOSQ_ERR_PROTOCOL ;
goto handle_connect_error ;
}
}
}
# ifdef WITH_TLS
2014-06-14 22:42:24 +00:00
if ( context - > listener & & context - > listener - > ssl_ctx & & context - > listener - > use_identity_as_username ) {
2014-05-07 22:27:00 +00:00
if ( ! context - > ssl ) {
2015-04-19 21:10:59 +00:00
mosquitto__send_connack ( 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 ;
}
# ifdef REAL_WITH_TLS_PSK
if ( context - > listener - > psk_hint ) {
/* Client should have provided an identity to get this far. */
if ( ! context - > username ) {
2015-04-19 21:10:59 +00:00
mosquitto__send_connack ( 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 {
# endif /* REAL_WITH_TLS_PSK */
client_cert = SSL_get_peer_certificate ( context - > ssl ) ;
if ( ! client_cert ) {
2015-04-19 21:10:59 +00:00
mosquitto__send_connack ( 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 ) {
2015-04-19 21:10:59 +00:00
mosquitto__send_connack ( 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 ;
}
i = X509_NAME_get_index_by_NID ( name , NID_commonName , - 1 ) ;
if ( i = = - 1 ) {
2015-04-19 21:10:59 +00:00
mosquitto__send_connack ( 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_entry = X509_NAME_get_entry ( name , i ) ;
2015-04-19 21:10:59 +00:00
context - > username = mosquitto__strdup ( ( char * ) ASN1_STRING_data ( name_entry - > value ) ) ;
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 ;
2014-05-07 22:27:00 +00:00
# ifdef REAL_WITH_TLS_PSK
}
# endif /* REAL_WITH_TLS_PSK */
} else {
# endif /* WITH_TLS */
if ( username_flag ) {
rc = mosquitto_unpwd_check ( db , username , password ) ;
2014-07-13 20:20:18 +00:00
switch ( rc ) {
case MOSQ_ERR_SUCCESS :
break ;
case MOSQ_ERR_AUTH :
2015-04-19 21:10:59 +00:00
mosquitto__send_connack ( context , 0 , CONNACK_REFUSED_BAD_USERNAME_PASSWORD ) ;
2014-07-13 20:20:18 +00:00
mqtt3_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 :
mqtt3_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 ;
}
if ( ! username_flag & & db - > config - > allow_anonymous = = false ) {
2015-04-19 21:10:59 +00:00
mosquitto__send_connack ( context , 0 , CONNACK_REFUSED_NOT_AUTHORIZED ) ;
2014-10-12 22:58:49 +00:00
rc = 1 ;
2014-05-07 22:27:00 +00:00
goto handle_connect_error ;
}
# 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 {
2015-04-19 21:10:59 +00:00
mosquitto__send_connack ( 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
* done in mqtt3_context_cleanup ( ) below . */
2014-05-07 22:27:00 +00:00
if ( db - > config - > connection_messages = = true ) {
2015-04-19 21:10:59 +00:00
mosquitto__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
2014-05-31 14:20:40 +00:00
if ( context - > protocol = = mosq_p_mqtt311 ) {
if ( clean_session = = 0 ) {
connect_ack | = 0x01 ;
}
}
2014-06-30 05:58:56 +00:00
2014-07-03 00:00:57 +00:00
context - > clean_session = clean_session ;
2014-06-30 22:30:43 +00:00
2014-10-16 22:48:56 +00:00
if ( context - > clean_session = = false & & found_context - > clean_session = = false ) {
if ( found_context - > msgs ) {
context - > msgs = found_context - > msgs ;
found_context - > msgs = NULL ;
2014-11-17 23:46:02 +00:00
mqtt3_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 ;
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
found_context - > clean_session = true ;
found_context - > state = mosq_cs_disconnecting ;
do_disconnect ( db , found_context ) ;
2014-05-07 22:27:00 +00:00
}
/* Associate user with its ACL, assuming we have ACLs loaded. */
if ( db - > acl_list ) {
acl_tail = db - > acl_list ;
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 ;
}
if ( will_struct ) {
context - > will = will_struct ;
context - > will - > topic = will_topic ;
if ( will_payload ) {
context - > will - > payload = will_payload ;
context - > will - > payloadlen = will_payloadlen ;
} else {
context - > will - > payload = NULL ;
context - > will - > payloadlen = 0 ;
}
context - > will - > qos = will_qos ;
context - > will - > retain = will_retain ;
}
if ( db - > config - > connection_messages = = true ) {
if ( context - > is_bridge ) {
if ( context - > username ) {
2015-04-19 21:10:59 +00:00
mosquitto__log_printf ( NULL , MOSQ_LOG_NOTICE , " New bridge connected from %s as %s (c%d, k%d, u'%s'). " , context - > address , client_id , clean_session , context - > keepalive , context - > username ) ;
2014-05-07 22:27:00 +00:00
} else {
2015-04-19 21:10:59 +00:00
mosquitto__log_printf ( NULL , MOSQ_LOG_NOTICE , " New bridge connected from %s as %s (c%d, k%d). " , context - > address , client_id , clean_session , context - > keepalive ) ;
2014-05-07 22:27:00 +00:00
}
} else {
if ( context - > username ) {
2015-04-19 21:10:59 +00:00
mosquitto__log_printf ( NULL , MOSQ_LOG_NOTICE , " New client connected from %s as %s (c%d, k%d, u'%s'). " , context - > address , client_id , clean_session , context - > keepalive , context - > username ) ;
2014-05-07 22:27:00 +00:00
} else {
2015-04-19 21:10:59 +00:00
mosquitto__log_printf ( NULL , MOSQ_LOG_NOTICE , " New client connected from %s as %s (c%d, k%d). " , context - > address , client_id , clean_session , context - > keepalive ) ;
2014-05-07 22:27:00 +00:00
}
}
}
2014-06-02 21:08:40 +00:00
context - > id = client_id ;
client_id = NULL ;
context - > clean_session = clean_session ;
context - > ping_t = 0 ;
context - > is_dropping = false ;
if ( ( protocol_version & 0x80 ) = = 0x80 ) {
context - > is_bridge = true ;
}
2014-06-13 22:07:00 +00:00
/* Remove any queued messages that are no longer allowed through ACL,
* assuming a possible change of username . */
msg_tail = context - > msgs ;
msg_prev = NULL ;
while ( msg_tail ) {
if ( msg_tail - > direction = = mosq_md_out ) {
2015-04-11 20:17:16 +00:00
if ( mosquitto_acl_check ( db , context , msg_tail - > store - > topic , MOSQ_ACL_READ ) ! = MOSQ_ERR_SUCCESS ) {
2014-11-19 20:59:10 +00:00
mosquitto__db_msg_store_deref ( db , & msg_tail - > store ) ;
2014-06-13 22:07:00 +00:00
if ( msg_prev ) {
msg_prev - > next = msg_tail - > next ;
2015-04-19 21:10:59 +00:00
mosquitto__free ( msg_tail ) ;
2014-06-13 22:07:00 +00:00
msg_tail = msg_prev - > next ;
} else {
context - > msgs = context - > msgs - > next ;
2015-04-19 21:10:59 +00:00
mosquitto__free ( msg_tail ) ;
2014-06-13 22:07:00 +00:00
msg_tail = context - > msgs ;
}
} else {
msg_prev = msg_tail ;
msg_tail = msg_tail - > next ;
}
} else {
msg_prev = msg_tail ;
msg_tail = msg_tail - > next ;
}
}
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
if ( ! clean_session ) {
db - > persistence_changes + + ;
}
# endif
2014-05-07 22:27:00 +00:00
context - > state = mosq_cs_connected ;
2015-04-19 21:10:59 +00:00
return mosquitto__send_connack ( context , connect_ack , CONNACK_ACCEPTED ) ;
2014-05-07 22:27:00 +00:00
handle_connect_error :
2015-04-19 21:10:59 +00:00
if ( client_id ) mosquitto__free ( client_id ) ;
if ( username ) mosquitto__free ( username ) ;
if ( password ) mosquitto__free ( password ) ;
if ( will_payload ) mosquitto__free ( will_payload ) ;
if ( will_topic ) mosquitto__free ( will_topic ) ;
if ( will_struct ) 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 ;
}
int mqtt3_handle_disconnect ( struct mosquitto_db * db , struct mosquitto * context )
{
if ( ! context ) {
return MOSQ_ERR_INVAL ;
}
if ( context - > in_packet . remaining_length ! = 0 ) {
return MOSQ_ERR_PROTOCOL ;
}
2015-04-19 21:10:59 +00:00
mosquitto__log_printf ( NULL , MOSQ_LOG_DEBUG , " Received DISCONNECT from %s " , context - > id ) ;
2014-05-07 22:27:00 +00:00
if ( context - > protocol = = mosq_p_mqtt311 ) {
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 ;
}
int mqtt3_handle_subscribe ( struct mosquitto_db * db , struct mosquitto * context )
{
int rc = 0 ;
int rc2 ;
uint16_t mid ;
char * sub ;
uint8_t qos ;
uint8_t * payload = NULL , * tmp_payload ;
uint32_t payloadlen = 0 ;
int len ;
char * sub_mount ;
if ( ! context ) return MOSQ_ERR_INVAL ;
2015-04-19 21:10:59 +00:00
mosquitto__log_printf ( NULL , MOSQ_LOG_DEBUG , " Received SUBSCRIBE from %s " , context - > id ) ;
2014-05-07 22:27:00 +00:00
/* FIXME - plenty of potential for memory leaks here */
if ( context - > protocol = = mosq_p_mqtt311 ) {
if ( ( context - > in_packet . command & 0x0F ) ! = 0x02 ) {
return MOSQ_ERR_PROTOCOL ;
}
}
2015-04-19 21:10:59 +00:00
if ( mosquitto__read_uint16 ( & context - > in_packet , & mid ) ) return 1 ;
2014-05-07 22:27:00 +00:00
while ( context - > in_packet . pos < context - > in_packet . remaining_length ) {
sub = NULL ;
2015-04-19 21:10:59 +00:00
if ( mosquitto__read_string ( & context - > in_packet , & sub ) ) {
if ( payload ) mosquitto__free ( payload ) ;
2014-05-07 22:27:00 +00:00
return 1 ;
}
if ( sub ) {
if ( ! strlen ( sub ) ) {
2015-04-19 21:10:59 +00:00
mosquitto__log_printf ( NULL , MOSQ_LOG_INFO , " Empty subscription string from %s, disconnecting. " ,
2014-05-07 22:27:00 +00:00
context - > address ) ;
2015-04-19 21:10:59 +00:00
mosquitto__free ( sub ) ;
if ( payload ) mosquitto__free ( payload ) ;
2014-05-07 22:27:00 +00:00
return 1 ;
}
2014-09-10 14:57:20 +00:00
if ( mosquitto_sub_topic_check ( sub ) ) {
2015-04-19 21:10:59 +00:00
mosquitto__log_printf ( NULL , MOSQ_LOG_INFO , " Invalid subscription string from %s, disconnecting. " ,
2014-05-07 22:27:00 +00:00
context - > address ) ;
2015-04-19 21:10:59 +00:00
mosquitto__free ( sub ) ;
if ( payload ) mosquitto__free ( payload ) ;
2014-05-07 22:27:00 +00:00
return 1 ;
}
2015-04-19 21:10:59 +00:00
if ( mosquitto__read_byte ( & context - > in_packet , & qos ) ) {
mosquitto__free ( sub ) ;
if ( payload ) mosquitto__free ( payload ) ;
2014-05-07 22:27:00 +00:00
return 1 ;
}
if ( qos > 2 ) {
2015-04-19 21:10:59 +00:00
mosquitto__log_printf ( NULL , MOSQ_LOG_INFO , " Invalid QoS in subscription command from %s, disconnecting. " ,
2014-05-07 22:27:00 +00:00
context - > address ) ;
2015-04-19 21:10:59 +00:00
mosquitto__free ( sub ) ;
if ( payload ) mosquitto__free ( payload ) ;
2014-05-07 22:27:00 +00:00
return 1 ;
}
if ( context - > listener & & context - > listener - > mount_point ) {
len = strlen ( context - > listener - > mount_point ) + strlen ( sub ) + 1 ;
2015-04-19 21:10:59 +00:00
sub_mount = mosquitto__malloc ( len + 1 ) ;
2014-05-07 22:27:00 +00:00
if ( ! sub_mount ) {
2015-04-19 21:10:59 +00:00
mosquitto__free ( sub ) ;
if ( payload ) mosquitto__free ( payload ) ;
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_NOMEM ;
}
snprintf ( sub_mount , len , " %s%s " , context - > listener - > mount_point , sub ) ;
2014-11-17 21:58:53 +00:00
sub_mount [ len ] = ' \0 ' ;
2015-04-19 21:10:59 +00:00
mosquitto__free ( sub ) ;
2014-05-07 22:27:00 +00:00
sub = sub_mount ;
}
2015-04-19 21:10:59 +00:00
mosquitto__log_printf ( NULL , MOSQ_LOG_DEBUG , " \t %s (QoS %d) " , sub , qos ) ;
2014-05-07 22:27:00 +00:00
2014-10-08 20:16:34 +00:00
#if 0
/* FIXME
* This section has been disabled temporarily . mosquitto_acl_check
* calls mosquitto_topic_matches_sub , which can ' t cope with
* checking subscriptions that have wildcards against ACLs that
* have wildcards . Bug # 1374291 is related .
*
* It ' s a very difficult problem when an ACL looks like foo / + / bar
* and a subscription request to foo / # is made .
*
* This should be changed to using MOSQ_ACL_SUBSCRIPTION in the
* future anyway .
*/
2014-05-07 22:27:00 +00:00
if ( context - > protocol = = mosq_p_mqtt311 ) {
rc = mosquitto_acl_check ( db , context , sub , MOSQ_ACL_READ ) ;
2014-07-13 20:20:18 +00:00
switch ( rc ) {
case MOSQ_ERR_SUCCESS :
break ;
case MOSQ_ERR_ACL_DENIED :
qos = 0x80 ;
break ;
default :
2015-04-19 21:10:59 +00:00
mosquitto__free ( sub ) ;
2014-07-13 20:20:18 +00:00
return rc ;
2014-05-07 22:27:00 +00:00
}
}
2014-10-08 20:16:34 +00:00
# endif
2014-05-07 22:27:00 +00:00
if ( qos ! = 0x80 ) {
rc2 = mqtt3_sub_add ( db , context , sub , qos , & db - > subs ) ;
if ( rc2 = = MOSQ_ERR_SUCCESS ) {
if ( mqtt3_retain_queue ( db , context , sub , qos ) ) rc = 1 ;
} else if ( rc2 ! = - 1 ) {
rc = rc2 ;
}
2015-04-19 21:10:59 +00:00
mosquitto__log_printf ( NULL , MOSQ_LOG_SUBSCRIBE , " %s %d %s " , context - > id , qos , sub ) ;
2014-05-07 22:27:00 +00:00
}
2015-04-19 21:10:59 +00:00
mosquitto__free ( sub ) ;
2014-05-07 22:27:00 +00:00
2015-04-19 21:10:59 +00:00
tmp_payload = mosquitto__realloc ( payload , payloadlen + 1 ) ;
2014-05-07 22:27:00 +00:00
if ( tmp_payload ) {
payload = tmp_payload ;
payload [ payloadlen ] = qos ;
payloadlen + + ;
} else {
2015-04-19 21:10:59 +00:00
if ( payload ) mosquitto__free ( payload ) ;
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_NOMEM ;
}
}
}
if ( context - > protocol = = mosq_p_mqtt311 ) {
if ( payloadlen = = 0 ) {
/* No subscriptions specified, protocol error. */
return MOSQ_ERR_PROTOCOL ;
}
}
2015-04-19 21:10:59 +00:00
if ( mosquitto__send_suback ( context , mid , payloadlen , payload ) ) rc = 1 ;
mosquitto__free ( payload ) ;
2014-05-07 22:27:00 +00:00
# ifdef WITH_PERSISTENCE
db - > persistence_changes + + ;
# endif
return rc ;
}
int mqtt3_handle_unsubscribe ( struct mosquitto_db * db , struct mosquitto * context )
{
uint16_t mid ;
char * sub ;
if ( ! context ) return MOSQ_ERR_INVAL ;
2015-04-19 21:10:59 +00:00
mosquitto__log_printf ( NULL , MOSQ_LOG_DEBUG , " Received UNSUBSCRIBE from %s " , context - > id ) ;
2014-05-07 22:27:00 +00:00
if ( context - > protocol = = mosq_p_mqtt311 ) {
if ( ( context - > in_packet . command & 0x0F ) ! = 0x02 ) {
return MOSQ_ERR_PROTOCOL ;
}
}
2015-04-19 21:10:59 +00:00
if ( mosquitto__read_uint16 ( & context - > in_packet , & mid ) ) return 1 ;
2014-05-07 22:27:00 +00:00
while ( context - > in_packet . pos < context - > in_packet . remaining_length ) {
sub = NULL ;
2015-04-19 21:10:59 +00:00
if ( mosquitto__read_string ( & context - > in_packet , & sub ) ) {
2014-05-07 22:27:00 +00:00
return 1 ;
}
if ( sub ) {
if ( ! strlen ( sub ) ) {
2015-04-19 21:10:59 +00:00
mosquitto__log_printf ( NULL , MOSQ_LOG_INFO , " Empty unsubscription string from %s, disconnecting. " ,
2014-05-07 22:27:00 +00:00
context - > id ) ;
2015-04-19 21:10:59 +00:00
mosquitto__free ( sub ) ;
2014-05-07 22:27:00 +00:00
return 1 ;
}
2014-09-10 14:57:20 +00:00
if ( mosquitto_sub_topic_check ( sub ) ) {
2015-04-19 21:10:59 +00:00
mosquitto__log_printf ( NULL , MOSQ_LOG_INFO , " Invalid unsubscription string from %s, disconnecting. " ,
2014-05-07 22:27:00 +00:00
context - > id ) ;
2015-04-19 21:10:59 +00:00
mosquitto__free ( sub ) ;
2014-05-07 22:27:00 +00:00
return 1 ;
}
2015-04-19 21:10:59 +00:00
mosquitto__log_printf ( NULL , MOSQ_LOG_DEBUG , " \t %s " , sub ) ;
2014-05-07 22:27:00 +00:00
mqtt3_sub_remove ( db , context , sub , & db - > subs ) ;
2015-04-19 21:10:59 +00:00
mosquitto__log_printf ( NULL , MOSQ_LOG_UNSUBSCRIBE , " %s %s " , context - > id , sub ) ;
mosquitto__free ( sub ) ;
2014-05-07 22:27:00 +00:00
}
}
# ifdef WITH_PERSISTENCE
db - > persistence_changes + + ;
# endif
2015-04-19 21:10:59 +00:00
return mosquitto__send_command_with_mid ( context , UNSUBACK , mid , false ) ;
2014-05-07 22:27:00 +00:00
}