1 /*
2 Copyright (c) 2009-2020 Roger Light <roger@atchoo.org>
3 
4 All rights reserved. This program and the accompanying materials
5 are made available under the terms of the Eclipse Public License v1.0
6 and Eclipse Distribution License v1.0 which accompany this distribution.
7 
8 The Eclipse Public License is available at
9    http://www.eclipse.org/legal/epl-v10.html
10 and the Eclipse Distribution License is available at
11   http://www.eclipse.org/org/documents/edl-v10.php.
12 
13 Contributors:
14    Roger Light - initial implementation and documentation.
15 */
16 
17 #include "config.h"
18 
19 #include <stdio.h>
20 #include <string.h>
21 
22 #include "mosquitto_broker_internal.h"
23 #include "memory_mosq.h"
24 #include "mqtt_protocol.h"
25 #include "packet_mosq.h"
26 #include "send_mosq.h"
27 #include "util_mosq.h"
28 
handle__connack(struct mosquitto_db * db,struct mosquitto * context)29 int handle__connack(struct mosquitto_db *db, struct mosquitto *context)
30 {
31 	int rc;
32 	uint8_t connect_acknowledge;
33 	uint8_t reason_code;
34 	int i;
35 	char *notification_topic;
36 	int notification_topic_len;
37 	char notification_payload;
38 	mosquitto_property *properties = NULL;
39 
40 	if(!context){
41 		return MOSQ_ERR_INVAL;
42 	}
43 	log__printf(NULL, MOSQ_LOG_DEBUG, "Received CONNACK on connection %s.", context->id);
44 	if(packet__read_byte(&context->in_packet, &connect_acknowledge)) return 1;
45 	if(packet__read_byte(&context->in_packet, &reason_code)) return 1;
46 
47 	if(context->protocol == mosq_p_mqtt5){
48 		rc = property__read_all(CMD_CONNACK, &context->in_packet, &properties);
49 		if(rc) return rc;
50 		mosquitto_property_free_all(&properties);
51 	}
52 	mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */
53 
54 	switch(reason_code){
55 		case CONNACK_ACCEPTED:
56 			if(context->bridge){
57 				if(context->bridge->notifications){
58 					notification_payload = '1';
59 					if(context->bridge->notification_topic){
60 						if(!context->bridge->notifications_local_only){
61 							if(send__real_publish(context, mosquitto__mid_generate(context),
62 									context->bridge->notification_topic, 1, &notification_payload, 1, true, 0, NULL, NULL, 0)){
63 
64 								return 1;
65 							}
66 						}
67 						db__messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, &notification_payload, 1, 0, NULL);
68 					}else{
69 						notification_topic_len = strlen(context->bridge->remote_clientid)+strlen("$SYS/broker/connection//state");
70 						notification_topic = mosquitto__malloc(sizeof(char)*(notification_topic_len+1));
71 						if(!notification_topic) return MOSQ_ERR_NOMEM;
72 
73 						snprintf(notification_topic, notification_topic_len+1, "$SYS/broker/connection/%s/state", context->bridge->remote_clientid);
74 						notification_payload = '1';
75 						if(!context->bridge->notifications_local_only){
76 							if(send__real_publish(context, mosquitto__mid_generate(context),
77 									notification_topic, 1, &notification_payload, 1, true, 0, NULL, NULL, 0)){
78 
79 								mosquitto__free(notification_topic);
80 								return 1;
81 							}
82 						}
83 						db__messages_easy_queue(db, context, notification_topic, 1, 1, &notification_payload, 1, 0, NULL);
84 						mosquitto__free(notification_topic);
85 					}
86 				}
87 				for(i=0; i<context->bridge->topic_count; i++){
88 					if(context->bridge->topics[i].direction == bd_in || context->bridge->topics[i].direction == bd_both){
89 						if(send__subscribe(context, NULL, 1, &context->bridge->topics[i].remote_topic, context->bridge->topics[i].qos, NULL)){
90 							return 1;
91 						}
92 					}else{
93 						if(context->bridge->attempt_unsubscribe){
94 							if(send__unsubscribe(context, NULL, 1, &context->bridge->topics[i].remote_topic, NULL)){
95 								/* direction = inwards only. This means we should not be subscribed
96 								* to the topic. It is possible that we used to be subscribed to
97 								* this topic so unsubscribe. */
98 								return 1;
99 							}
100 						}
101 					}
102 				}
103 				for(i=0; i<context->bridge->topic_count; i++){
104 					if(context->bridge->topics[i].direction == bd_out || context->bridge->topics[i].direction == bd_both){
105 						sub__retain_queue(db, context,
106 								context->bridge->topics[i].local_topic,
107 								context->bridge->topics[i].qos, 0);
108 					}
109 				}
110 			}
111 			mosquitto__set_state(context, mosq_cs_active);
112 			return MOSQ_ERR_SUCCESS;
113 		case CONNACK_REFUSED_PROTOCOL_VERSION:
114 			if(context->bridge){
115 				context->bridge->try_private_accepted = false;
116 			}
117 			log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: unacceptable protocol version");
118 			return 1;
119 		case CONNACK_REFUSED_IDENTIFIER_REJECTED:
120 			log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: identifier rejected");
121 			return 1;
122 		case CONNACK_REFUSED_SERVER_UNAVAILABLE:
123 			log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: broker unavailable");
124 			return 1;
125 		case CONNACK_REFUSED_BAD_USERNAME_PASSWORD:
126 			log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: broker unavailable");
127 			return 1;
128 		case CONNACK_REFUSED_NOT_AUTHORIZED:
129 			log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: not authorised");
130 			return 1;
131 		default:
132 			log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: unknown reason");
133 			return 1;
134 	}
135 	return 1;
136 }
137 
138