1 /*
2 * Copyright (c) 2021 One Identity
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published
6 * by the Free Software Foundation, or (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 *
17 * As an additional exemption you are allowed to compile & link against the
18 * OpenSSL libraries as published by the OpenSSL project. See the file
19 * COPYING for details.
20 *
21 */
22
23 #include "mqtt-options.h"
24 #include "syslog-ng.h"
25
26 #include <MQTTClient.h>
27 #include <string.h>
28 #include <stddef.h>
29
30
31 #define DEFAULT_ADDRESS "tcp://localhost:1883"
32 #define DEFAULT_KEEPALIVE 60
33 #define DEFAULT_QOS 0
34
35
36
37 static gboolean
_validate_protocol(const gchar * address)38 _validate_protocol(const gchar *address)
39 {
40 const gchar *valid_type[] = {"tcp", "ssl", "ws", "wss"};
41 gint i;
42
43 for (i = 0; i < G_N_ELEMENTS(valid_type); ++i)
44 if (strncmp(valid_type[i], address, strlen(valid_type[i])) == 0)
45 return TRUE;
46
47 return FALSE;
48 }
49
50 static gboolean
_validate_address(const gchar * address)51 _validate_address(const gchar *address)
52 {
53 if (strstr(address, "://") == NULL)
54 return FALSE;
55
56 if (!_validate_protocol(address))
57 return FALSE;
58
59 return TRUE;
60 }
61
62 void
mqtt_client_options_defaults(MQTTClientOptions * self)63 mqtt_client_options_defaults(MQTTClientOptions *self)
64 {
65 self->address = g_strdup(DEFAULT_ADDRESS);
66 self->keepalive = DEFAULT_KEEPALIVE;
67 self->qos = DEFAULT_QOS;
68
69 self->ssl_version = MQTT_SSL_VERSION_DEFAULT;
70 self->peer_verify = TRUE;
71 self->use_system_cert_store = FALSE;
72 }
73
74 void
mqtt_client_options_destroy(MQTTClientOptions * self)75 mqtt_client_options_destroy(MQTTClientOptions *self)
76 {
77 g_free(self->address);
78 g_free(self->client_id);
79
80 g_free(self->username);
81 g_free(self->password);
82 g_free(self->http_proxy);
83
84 g_free(self->ca_dir);
85 g_free(self->ca_file);
86 g_free(self->cert_file);
87 g_free(self->key_file);
88 g_free(self->ciphers);
89 }
90
91 void
mqtt_client_options_set_keepalive(MQTTClientOptions * self,const gint keepalive)92 mqtt_client_options_set_keepalive(MQTTClientOptions *self, const gint keepalive)
93 {
94 self->keepalive = keepalive;
95 }
96
97 gboolean
mqtt_client_options_set_address(MQTTClientOptions * self,const gchar * address)98 mqtt_client_options_set_address(MQTTClientOptions *self, const gchar *address)
99 {
100 if (!_validate_address(address))
101 return FALSE;
102
103 g_free(self->address);
104 self->address = g_strdup(address);
105 return TRUE;
106 }
107
108 void
mqtt_client_options_set_qos(MQTTClientOptions * self,const gint qos)109 mqtt_client_options_set_qos (MQTTClientOptions *self, const gint qos)
110 {
111 self->qos = qos;
112 }
113
114 gboolean
mqtt_client_options_set_client_id(MQTTClientOptions * self,const gchar * client_id)115 mqtt_client_options_set_client_id(MQTTClientOptions *self, const gchar *client_id)
116 {
117 if(strcmp("", client_id) == 0)
118 return FALSE;
119
120 g_free(self->client_id);
121 self->client_id = g_strdup(client_id);
122
123 return TRUE;
124 }
125
126 void
mqtt_client_options_set_cleansession(MQTTClientOptions * self,gboolean cleansession)127 mqtt_client_options_set_cleansession(MQTTClientOptions *self, gboolean cleansession)
128 {
129 self->cleansession = cleansession;
130 }
131
132 void
mqtt_client_options_set_username(MQTTClientOptions * self,const gchar * username)133 mqtt_client_options_set_username(MQTTClientOptions *self, const gchar *username)
134 {
135 g_free(self->username);
136 self->username = g_strdup(username);
137 }
138
139 void
mqtt_client_options_set_password(MQTTClientOptions * self,const gchar * password)140 mqtt_client_options_set_password(MQTTClientOptions *self, const gchar *password)
141 {
142 g_free(self->password);
143 self->password = g_strdup(password);
144 }
145
146 void
mqtt_client_options_set_http_proxy(MQTTClientOptions * self,const gchar * http_proxy)147 mqtt_client_options_set_http_proxy(MQTTClientOptions *self, const gchar *http_proxy)
148 {
149 g_free(self->http_proxy);
150 self->http_proxy = g_strdup(http_proxy);
151 }
152
153
154 void
mqtt_client_options_set_ca_dir(MQTTClientOptions * self,const gchar * ca_dir)155 mqtt_client_options_set_ca_dir(MQTTClientOptions *self, const gchar *ca_dir)
156 {
157 g_free(self->ca_dir);
158 self->ca_dir = g_strdup(ca_dir);
159 }
160
161 void
mqtt_client_options_set_ca_file(MQTTClientOptions * self,const gchar * ca_file)162 mqtt_client_options_set_ca_file(MQTTClientOptions *self, const gchar *ca_file)
163 {
164 g_free(self->ca_file);
165 self->ca_file = g_strdup(ca_file);
166 }
167
168 void
mqtt_client_options_set_cert_file(MQTTClientOptions * self,const gchar * cert_file)169 mqtt_client_options_set_cert_file(MQTTClientOptions *self, const gchar *cert_file)
170 {
171 g_free(self->cert_file);
172 self->cert_file = g_strdup(cert_file);
173 }
174
175 void
mqtt_client_options_set_key_file(MQTTClientOptions * self,const gchar * key_file)176 mqtt_client_options_set_key_file(MQTTClientOptions *self, const gchar *key_file)
177 {
178 g_free(self->key_file);
179 self->key_file = g_strdup(key_file);
180 }
181
182 void
mqtt_client_options_set_cipher_suite(MQTTClientOptions * self,const gchar * ciphers)183 mqtt_client_options_set_cipher_suite(MQTTClientOptions *self, const gchar *ciphers)
184 {
185 g_free(self->ciphers);
186 self->ciphers = g_strdup(ciphers);
187 }
188
189 gboolean
mqtt_client_options_set_ssl_version(MQTTClientOptions * self,const gchar * value)190 mqtt_client_options_set_ssl_version(MQTTClientOptions *self, const gchar *value)
191 {
192 if (strcasecmp(value, "default") == 0)
193 self->ssl_version = MQTT_SSL_VERSION_DEFAULT;
194 else if (strcasecmp(value, "tlsv1_0") == 0)
195 self->ssl_version = MQTT_SSL_VERSION_TLS_1_0;
196 else if (strcasecmp(value, "tlsv1_1") == 0)
197 self->ssl_version = MQTT_SSL_VERSION_TLS_1_1;
198 else if (strcasecmp(value, "tlsv1_2") == 0)
199 self->ssl_version = MQTT_SSL_VERSION_TLS_1_2;
200 else
201 return FALSE;
202
203 return TRUE;
204 }
205
206 void
mqtt_client_options_set_peer_verify(MQTTClientOptions * self,gboolean verify)207 mqtt_client_options_set_peer_verify(MQTTClientOptions *self, gboolean verify)
208 {
209 self->peer_verify = verify;
210 }
211
212 void
mqtt_client_options_use_system_cert_store(MQTTClientOptions * self,gboolean use_system_cert_store)213 mqtt_client_options_use_system_cert_store(MQTTClientOptions *self, gboolean use_system_cert_store)
214 {
215 /* TODO: auto_detect_ca_file() from the HTTP module */
216 self->use_system_cert_store = use_system_cert_store;
217 }
218
219 void
mqtt_client_options_set_log_ssl_error_fn(MQTTClientOptions * self,gpointer context,gint (* log_error)(const gchar * str,gsize len,gpointer u))220 mqtt_client_options_set_log_ssl_error_fn(MQTTClientOptions *self, gpointer context, gint(*log_error)(const gchar *str,
221 gsize len, gpointer u))
222 {
223 self->context = context;
224 self->log_error = log_error;
225 }
226
227 gchar *
mqtt_client_options_get_address(MQTTClientOptions * self)228 mqtt_client_options_get_address(MQTTClientOptions *self)
229 {
230 return self->address;
231 }
232
233 gint
mqtt_client_options_get_qos(MQTTClientOptions * self)234 mqtt_client_options_get_qos(MQTTClientOptions *self)
235 {
236 return self->qos;
237 }
238
239 gchar *
mqtt_client_options_get_client_id(MQTTClientOptions * self)240 mqtt_client_options_get_client_id(MQTTClientOptions *self)
241 {
242 return self->client_id;
243 }
244
245 static void
_set_ssl_options(MQTTClientOptions * self,MQTTClient_SSLOptions * ssl_opts)246 _set_ssl_options(MQTTClientOptions *self, MQTTClient_SSLOptions *ssl_opts)
247 {
248 *ssl_opts = (MQTTClient_SSLOptions) MQTTClient_SSLOptions_initializer;
249 ssl_opts->trustStore = self->ca_file;
250 ssl_opts->CApath = self->ca_dir;
251 ssl_opts->keyStore = self->cert_file;
252 ssl_opts->privateKey = self->key_file;
253 ssl_opts->enabledCipherSuites = self->ciphers;
254 ssl_opts->sslVersion = self->ssl_version;
255 ssl_opts->enableServerCertAuth = self->peer_verify;
256 ssl_opts->verify = self->peer_verify;
257 ssl_opts->disableDefaultTrustStore = !self->use_system_cert_store;
258 ssl_opts->ssl_error_cb = self->log_error;
259 ssl_opts->ssl_error_context = self->context;
260 }
261
262 void
mqtt_client_options_to_mqtt_client_connection_option(MQTTClientOptions * self,MQTTClient_connectOptions * conn_opts,MQTTClient_SSLOptions * ssl_opts)263 mqtt_client_options_to_mqtt_client_connection_option(MQTTClientOptions *self, MQTTClient_connectOptions *conn_opts,
264 MQTTClient_SSLOptions *ssl_opts)
265 {
266 *conn_opts = (MQTTClient_connectOptions) MQTTClient_connectOptions_initializer;
267 conn_opts->keepAliveInterval = self->keepalive;
268 conn_opts->cleansession = self->cleansession;
269 conn_opts->username = self->username;
270 conn_opts->password = self->password;
271
272 #if SYSLOG_NG_HAVE_PAHO_HTTP_PROXY
273 if (self->http_proxy)
274 {
275 conn_opts->httpProxy = self->http_proxy;
276 conn_opts->httpsProxy = self->http_proxy;
277 }
278 #endif
279
280 _set_ssl_options(self, ssl_opts);
281 conn_opts->ssl = ssl_opts;
282 }
283
284 static gboolean
_key_or_cert_file_is_not_specified(MQTTClientOptions * self)285 _key_or_cert_file_is_not_specified(MQTTClientOptions *self)
286 {
287 return (!self->key_file || !self->cert_file);
288 }
289
290 static gboolean
_is_using_tls(MQTTClientOptions * self)291 _is_using_tls(MQTTClientOptions *self)
292 {
293 return (strncmp("ssl", self->address, 3) == 0) ||
294 (strncmp("wss", self->address, 3) == 0);
295 }
296
297 gboolean
mqtt_client_options_checker(MQTTClientOptions * self)298 mqtt_client_options_checker(MQTTClientOptions *self)
299 {
300
301 #if !SYSLOG_NG_HAVE_PAHO_HTTP_PROXY
302 if (self->http_proxy)
303 {
304 msg_warning_once("WARNING: the http-proxy() option of the mqtt() destination "
305 "is not supported on the current libpaho-mqtt version. "
306 "If you would like to use this feature, update to at least libpaho-mqtt 1.3.7");
307 g_free(self->http_proxy);
308 self->http_proxy = NULL;
309 }
310 #endif
311
312 if (_is_using_tls(self) && _key_or_cert_file_is_not_specified(self))
313 {
314 msg_warning("MQTT: You have a TLS enabled without a X.509 keypair."
315 " Make sure you have tls(key-file() and cert-file()) options, "
316 "TLS handshake to this source will fail");
317 }
318
319 return TRUE;
320 }
321