1 /*
2 Copyright (c) 2016-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 2.0
6 and Eclipse Distribution License v1.0 which accompany this distribution.
7 
8 The Eclipse Public License is available at
9    https://www.eclipse.org/legal/epl-2.0/
10 and the Eclipse Distribution License is available at
11   http://www.eclipse.org/org/documents/edl-v10.php.
12 
13 SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
14 
15 Contributors:
16    Roger Light - initial implementation and documentation.
17 */
18 
19 #include "config.h"
20 
21 #include "mosquitto_broker_internal.h"
22 #include "mosquitto_internal.h"
23 #include "mosquitto_broker.h"
24 #include "memory_mosq.h"
25 #include "mqtt_protocol.h"
26 #include "send_mosq.h"
27 #include "util_mosq.h"
28 #include "utlist.h"
29 
30 #ifdef WITH_TLS
31 #  include <openssl/ssl.h>
32 #endif
33 
mosquitto_client_address(const struct mosquitto * client)34 const char *mosquitto_client_address(const struct mosquitto *client)
35 {
36 	if(client){
37 		return client->address;
38 	}else{
39 		return NULL;
40 	}
41 }
42 
43 
mosquitto_client_clean_session(const struct mosquitto * client)44 bool mosquitto_client_clean_session(const struct mosquitto *client)
45 {
46 	if(client){
47 		return client->clean_start;
48 	}else{
49 		return true;
50 	}
51 }
52 
53 
mosquitto_client_id(const struct mosquitto * client)54 const char *mosquitto_client_id(const struct mosquitto *client)
55 {
56 	if(client){
57 		return client->id;
58 	}else{
59 		return NULL;
60 	}
61 }
62 
63 
mosquitto_client_keepalive(const struct mosquitto * client)64 int mosquitto_client_keepalive(const struct mosquitto *client)
65 {
66 	if(client){
67 		return client->keepalive;
68 	}else{
69 		return -1;
70 	}
71 }
72 
73 
mosquitto_client_certificate(const struct mosquitto * client)74 void *mosquitto_client_certificate(const struct mosquitto *client)
75 {
76 #ifdef WITH_TLS
77 	if(client && client->ssl){
78 		return SSL_get_peer_certificate(client->ssl);
79 	}else{
80 		return NULL;
81 	}
82 #else
83 	UNUSED(client);
84 
85 	return NULL;
86 #endif
87 }
88 
89 
mosquitto_client_protocol(const struct mosquitto * client)90 int mosquitto_client_protocol(const struct mosquitto *client)
91 {
92 #ifdef WITH_WEBSOCKETS
93 	if(client && client->wsi){
94 		return mp_websockets;
95 	}else
96 #else
97 	UNUSED(client);
98 #endif
99 	{
100 		return mp_mqtt;
101 	}
102 }
103 
104 
mosquitto_client_protocol_version(const struct mosquitto * client)105 int mosquitto_client_protocol_version(const struct mosquitto *client)
106 {
107 	if(client){
108 		switch(client->protocol){
109 			case mosq_p_mqtt31:
110 				return 3;
111 			case mosq_p_mqtt311:
112 				return 4;
113 			case mosq_p_mqtt5:
114 				return 5;
115 			default:
116 				return 0;
117 		}
118 	}else{
119 		return 0;
120 	}
121 }
122 
123 
mosquitto_client_sub_count(const struct mosquitto * client)124 int mosquitto_client_sub_count(const struct mosquitto *client)
125 {
126 	if(client){
127 		return client->sub_count;
128 	}else{
129 		return 0;
130 	}
131 }
132 
133 
mosquitto_client_username(const struct mosquitto * client)134 const char *mosquitto_client_username(const struct mosquitto *client)
135 {
136 	if(client){
137 #ifdef WITH_BRIDGE
138 		if(client->bridge){
139 			return client->bridge->local_username;
140 		}else
141 #endif
142 		{
143 			return client->username;
144 		}
145 	}else{
146 		return NULL;
147 	}
148 }
149 
150 
mosquitto_broker_publish(const char * clientid,const char * topic,int payloadlen,void * payload,int qos,bool retain,mosquitto_property * properties)151 int mosquitto_broker_publish(
152 		const char *clientid,
153 		const char *topic,
154 		int payloadlen,
155 		void *payload,
156 		int qos,
157 		bool retain,
158 		mosquitto_property *properties)
159 {
160 	struct mosquitto_message_v5 *msg;
161 
162 	if(topic == NULL
163 			|| payloadlen < 0
164 			|| (payloadlen > 0 && payload == NULL)
165 			|| qos < 0 || qos > 2){
166 
167 		return MOSQ_ERR_INVAL;
168 	}
169 
170 	msg = mosquitto__malloc(sizeof(struct mosquitto_message_v5));
171 	if(msg == NULL) return MOSQ_ERR_NOMEM;
172 
173 	msg->next = NULL;
174 	msg->prev = NULL;
175 	if(clientid){
176 		msg->clientid = mosquitto__strdup(clientid);
177 		if(msg->clientid == NULL){
178 			mosquitto__free(msg);
179 			return MOSQ_ERR_NOMEM;
180 		}
181 	}else{
182 		msg->clientid = NULL;
183 	}
184 	msg->topic = mosquitto__strdup(topic);
185 	if(msg->topic == NULL){
186 		mosquitto__free(msg->clientid);
187 		mosquitto__free(msg);
188 		return MOSQ_ERR_NOMEM;
189 	}
190 	msg->payloadlen = payloadlen;
191 	msg->payload = payload;
192 	msg->qos = qos;
193 	msg->retain = retain;
194 	msg->properties = properties;
195 
196 	DL_APPEND(db.plugin_msgs, msg);
197 
198 	return MOSQ_ERR_SUCCESS;
199 }
200 
201 
mosquitto_broker_publish_copy(const char * clientid,const char * topic,int payloadlen,const void * payload,int qos,bool retain,mosquitto_property * properties)202 int mosquitto_broker_publish_copy(
203 		const char *clientid,
204 		const char *topic,
205 		int payloadlen,
206 		const void *payload,
207 		int qos,
208 		bool retain,
209 		mosquitto_property *properties)
210 {
211 	void *payload_out;
212 
213 	if(topic == NULL
214 			|| payloadlen < 0
215 			|| (payloadlen > 0 && payload == NULL)
216 			|| qos < 0 || qos > 2){
217 
218 		return MOSQ_ERR_INVAL;
219 	}
220 
221 	payload_out = calloc(1, (size_t)(payloadlen+1));
222 	if(payload_out == NULL){
223 		return MOSQ_ERR_NOMEM;
224 	}
225 	memcpy(payload_out, payload, (size_t)payloadlen);
226 
227 	return mosquitto_broker_publish(
228 			clientid,
229 			topic,
230 			payloadlen,
231 			payload_out,
232 			qos,
233 			retain,
234 			properties);
235 }
236 
237 
mosquitto_set_username(struct mosquitto * client,const char * username)238 int mosquitto_set_username(struct mosquitto *client, const char *username)
239 {
240 	char *u_dup;
241 	char *old;
242 	int rc;
243 
244 	if(!client) return MOSQ_ERR_INVAL;
245 
246 	if(username){
247 		u_dup = mosquitto__strdup(username);
248 		if(!u_dup) return MOSQ_ERR_NOMEM;
249 	}else{
250 		u_dup = NULL;
251 	}
252 
253 	old = client->username;
254 	client->username = u_dup;
255 
256 	rc = acl__find_acls(client);
257 	if(rc){
258 		client->username = old;
259 		mosquitto__free(u_dup);
260 		return rc;
261 	}else{
262 		mosquitto__free(old);
263 		return MOSQ_ERR_SUCCESS;
264 	}
265 }
266 
267 
268 /* Check to see whether durable clients still have rights to their subscriptions. */
check_subscription_acls(struct mosquitto * context)269 static void check_subscription_acls(struct mosquitto *context)
270 {
271 	int i;
272 	int rc;
273 	uint8_t reason;
274 
275 	for(i=0; i<context->sub_count; i++){
276 		if(context->subs[i] == NULL){
277 			continue;
278 		}
279 		rc = mosquitto_acl_check(context,
280 				context->subs[i]->topic_filter,
281 				0,
282 				NULL,
283 				0, /* FIXME */
284 				false,
285 				MOSQ_ACL_SUBSCRIBE);
286 
287 		if(rc != MOSQ_ERR_SUCCESS){
288 			sub__remove(context, context->subs[i]->topic_filter, db.subs, &reason);
289 		}
290 	}
291 }
292 
293 
294 
disconnect_client(struct mosquitto * context,bool with_will)295 static void disconnect_client(struct mosquitto *context, bool with_will)
296 {
297 	if(context->protocol == mosq_p_mqtt5){
298 		send__disconnect(context, MQTT_RC_ADMINISTRATIVE_ACTION, NULL);
299 	}
300 	if(with_will == false){
301 		mosquitto__set_state(context, mosq_cs_disconnecting);
302 	}
303 	if(context->session_expiry_interval > 0){
304 		check_subscription_acls(context);
305 	}
306 	do_disconnect(context, MOSQ_ERR_ADMINISTRATIVE_ACTION);
307 }
308 
mosquitto_kick_client_by_clientid(const char * clientid,bool with_will)309 int mosquitto_kick_client_by_clientid(const char *clientid, bool with_will)
310 {
311 	struct mosquitto *ctxt, *ctxt_tmp;
312 
313 	if(clientid == NULL){
314 		HASH_ITER(hh_sock, db.contexts_by_sock, ctxt, ctxt_tmp){
315 			disconnect_client(ctxt, with_will);
316 		}
317 		return MOSQ_ERR_SUCCESS;
318 	}else{
319 		HASH_FIND(hh_id, db.contexts_by_id, clientid, strlen(clientid), ctxt);
320 		if(ctxt){
321 			disconnect_client(ctxt, with_will);
322 			return MOSQ_ERR_SUCCESS;
323 		}else{
324 			return MOSQ_ERR_NOT_FOUND;
325 		}
326 	}
327 }
328 
mosquitto_kick_client_by_username(const char * username,bool with_will)329 int mosquitto_kick_client_by_username(const char *username, bool with_will)
330 {
331 	struct mosquitto *ctxt, *ctxt_tmp;
332 
333 	if(username == NULL){
334 		HASH_ITER(hh_sock, db.contexts_by_sock, ctxt, ctxt_tmp){
335 			if(ctxt->username == NULL){
336 				disconnect_client(ctxt, with_will);
337 			}
338 		}
339 	}else{
340 		HASH_ITER(hh_sock, db.contexts_by_sock, ctxt, ctxt_tmp){
341 			if(ctxt->username != NULL && !strcmp(ctxt->username, username)){
342 				disconnect_client(ctxt, with_will);
343 			}
344 		}
345 	}
346 	return MOSQ_ERR_SUCCESS;
347 }
348