UNPKG

71.4 kBtext/x-cView Raw
1/*
2Copyright (c) 2009-2013 Roger Light <roger@atchoo.org>
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7
81. Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
102. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
133. Neither the name of mosquitto nor the names of its
14 contributors may be used to endorse or promote products derived from
15 this software without specific prior written permission.
16
17THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27POSSIBILITY OF SUCH DAMAGE.
28*/
29
30#include <config.h>
31
32#include <limits.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <errno.h>
37
38#ifdef WIN32
39#else
40# include <dirent.h>
41#endif
42
43#ifndef WIN32
44# include <netdb.h>
45# include <sys/socket.h>
46#else
47# include <winsock2.h>
48# include <ws2tcpip.h>
49#endif
50
51#include <mosquitto_broker.h>
52#include <memory_mosq.h>
53#include "tls_mosq.h"
54#include "util_mosq.h"
55#include "mqtt3_protocol.h"
56
57struct config_recurse {
58 int log_dest;
59 int log_dest_set;
60 int log_type;
61 int log_type_set;
62 int max_inflight_messages;
63 int max_queued_messages;
64};
65
66#if defined(WIN32) || defined(__CYGWIN__)
67#include <windows.h>
68extern SERVICE_STATUS_HANDLE service_handle;
69#endif
70
71static int _conf_parse_bool(char **token, const char *name, bool *value, char *saveptr);
72static int _conf_parse_int(char **token, const char *name, int *value, char *saveptr);
73static int _conf_parse_string(char **token, const char *name, char **value, char *saveptr);
74static int _config_read_file(struct mqtt3_config *config, bool reload, const char *file, struct config_recurse *config_tmp, int level, int *lineno);
75
76static int _conf_attempt_resolve(const char *host, const char *text, int log, const char *msg)
77{
78 struct addrinfo gai_hints;
79 struct addrinfo *gai_res;
80 int rc;
81
82 memset(&gai_hints, 0, sizeof(struct addrinfo));
83 gai_hints.ai_family = PF_UNSPEC;
84 gai_hints.ai_flags = AI_ADDRCONFIG;
85 gai_hints.ai_socktype = SOCK_STREAM;
86 gai_res = NULL;
87 rc = getaddrinfo(host, NULL, &gai_hints, &gai_res);
88 if(gai_res){
89 freeaddrinfo(gai_res);
90 }
91 if(rc != 0){
92#ifndef WIN32
93 if(rc == EAI_SYSTEM){
94 if(errno == ENOENT){
95 _mosquitto_log_printf(NULL, log, "%s: Unable to resolve %s %s.", msg, text, host);
96 }else{
97 _mosquitto_log_printf(NULL, log, "%s: Error resolving %s: %s.", msg, text, strerror(errno));
98 }
99 }else{
100 _mosquitto_log_printf(NULL, log, "%s: Error resolving %s: %s.", msg, text, gai_strerror(rc));
101 }
102#else
103 if(rc == WSAHOST_NOT_FOUND){
104 _mosquitto_log_printf(NULL, log, "%s: Error resolving %s.", msg, text);
105 }
106#endif
107 return MOSQ_ERR_INVAL;
108 }
109 return MOSQ_ERR_SUCCESS;
110}
111
112static void _config_init_reload(struct mqtt3_config *config)
113{
114 int i;
115 /* Set defaults */
116 if(config->acl_file) _mosquitto_free(config->acl_file);
117 config->acl_file = NULL;
118 config->allow_anonymous = true;
119 config->allow_duplicate_messages = false;
120 config->allow_zero_length_clientid = true;
121 config->auto_id_prefix = NULL;
122 config->auto_id_prefix_len = 0;
123 config->autosave_interval = 1800;
124 config->autosave_on_changes = false;
125 if(config->clientid_prefixes) _mosquitto_free(config->clientid_prefixes);
126 config->connection_messages = true;
127 config->clientid_prefixes = NULL;
128 if(config->log_fptr){
129 fclose(config->log_fptr);
130 config->log_fptr = NULL;
131 }
132 if(config->log_file){
133 _mosquitto_free(config->log_file);
134 config->log_file = NULL;
135 }
136#if defined(WIN32) || defined(__CYGWIN__)
137 if(service_handle){
138 /* This is running as a Windows service. Default to no logging. Using
139 * stdout/stderr is forbidden because the first clients to connect will
140 * get log information sent to them for some reason. */
141 config->log_dest = MQTT3_LOG_NONE;
142 }else{
143 config->log_dest = MQTT3_LOG_STDERR;
144 }
145#else
146 config->log_dest = MQTT3_LOG_STDERR;
147 if(config->verbose){
148 config->log_type = INT_MAX;
149 }else{
150 config->log_type = MOSQ_LOG_ERR | MOSQ_LOG_WARNING | MOSQ_LOG_NOTICE | MOSQ_LOG_INFO;
151 }
152#endif
153 config->log_timestamp = true;
154 if(config->password_file) _mosquitto_free(config->password_file);
155 config->password_file = NULL;
156 config->persistence = false;
157 if(config->persistence_location) _mosquitto_free(config->persistence_location);
158 config->persistence_location = NULL;
159 if(config->persistence_file) _mosquitto_free(config->persistence_file);
160 config->persistence_file = NULL;
161 config->persistent_client_expiration = 0;
162 if(config->psk_file) _mosquitto_free(config->psk_file);
163 config->psk_file = NULL;
164 config->queue_qos0_messages = false;
165 config->retry_interval = 20;
166 config->store_clean_interval = 10;
167 config->sys_interval = 10;
168 config->upgrade_outgoing_qos = false;
169 if(config->auth_options){
170 for(i=0; i<config->auth_option_count; i++){
171 _mosquitto_free(config->auth_options[i].key);
172 _mosquitto_free(config->auth_options[i].value);
173 }
174 _mosquitto_free(config->auth_options);
175 config->auth_options = NULL;
176 config->auth_option_count = 0;
177 }
178}
179
180void mqtt3_config_init(struct mqtt3_config *config)
181{
182 memset(config, 0, sizeof(struct mqtt3_config));
183 _config_init_reload(config);
184 config->config_file = NULL;
185 config->daemon = false;
186 config->default_listener.host = NULL;
187 config->default_listener.port = 0;
188 config->default_listener.max_connections = -1;
189 config->default_listener.mount_point = NULL;
190 config->default_listener.socks = NULL;
191 config->default_listener.sock_count = 0;
192 config->default_listener.client_count = 0;
193#ifdef WITH_TLS
194 config->default_listener.tls_version = NULL;
195 config->default_listener.cafile = NULL;
196 config->default_listener.capath = NULL;
197 config->default_listener.certfile = NULL;
198 config->default_listener.keyfile = NULL;
199 config->default_listener.ciphers = NULL;
200 config->default_listener.psk_hint = NULL;
201 config->default_listener.require_certificate = false;
202 config->default_listener.crlfile = NULL;
203 config->default_listener.use_identity_as_username = false;
204#endif
205 config->listeners = NULL;
206 config->listener_count = 0;
207 config->pid_file = NULL;
208 config->user = NULL;
209#ifdef WITH_BRIDGE
210 config->bridges = NULL;
211 config->bridge_count = 0;
212#endif
213 config->auth_plugin = NULL;
214 config->verbose = false;
215 config->message_size_limit = 0;
216}
217
218void mqtt3_config_cleanup(struct mqtt3_config *config)
219{
220 int i;
221#ifdef WITH_BRIDGE
222 int j;
223#endif
224
225 if(config->acl_file) _mosquitto_free(config->acl_file);
226 if(config->auto_id_prefix) _mosquitto_free(config->auto_id_prefix);
227 if(config->clientid_prefixes) _mosquitto_free(config->clientid_prefixes);
228 if(config->config_file) _mosquitto_free(config->config_file);
229 if(config->password_file) _mosquitto_free(config->password_file);
230 if(config->persistence_location) _mosquitto_free(config->persistence_location);
231 if(config->persistence_file) _mosquitto_free(config->persistence_file);
232 if(config->persistence_filepath) _mosquitto_free(config->persistence_filepath);
233 if(config->psk_file) _mosquitto_free(config->psk_file);
234 if(config->listeners){
235 for(i=0; i<config->listener_count; i++){
236 if(config->listeners[i].host) _mosquitto_free(config->listeners[i].host);
237 if(config->listeners[i].mount_point) _mosquitto_free(config->listeners[i].mount_point);
238 if(config->listeners[i].socks) _mosquitto_free(config->listeners[i].socks);
239#ifdef WITH_TLS
240 if(config->listeners[i].cafile) _mosquitto_free(config->listeners[i].cafile);
241 if(config->listeners[i].capath) _mosquitto_free(config->listeners[i].capath);
242 if(config->listeners[i].certfile) _mosquitto_free(config->listeners[i].certfile);
243 if(config->listeners[i].keyfile) _mosquitto_free(config->listeners[i].keyfile);
244 if(config->listeners[i].ciphers) _mosquitto_free(config->listeners[i].ciphers);
245 if(config->listeners[i].psk_hint) _mosquitto_free(config->listeners[i].psk_hint);
246 if(config->listeners[i].crlfile) _mosquitto_free(config->listeners[i].crlfile);
247 if(config->listeners[i].tls_version) _mosquitto_free(config->listeners[i].tls_version);
248 if(config->listeners[i].ssl_ctx) SSL_CTX_free(config->listeners[i].ssl_ctx);
249#endif
250 }
251 _mosquitto_free(config->listeners);
252 }
253#ifdef WITH_BRIDGE
254 if(config->bridges){
255 for(i=0; i<config->bridge_count; i++){
256 if(config->bridges[i].name) _mosquitto_free(config->bridges[i].name);
257 if(config->bridges[i].addresses){
258 for(j=0; j<config->bridges[i].address_count; j++){
259 _mosquitto_free(config->bridges[i].addresses[j].address);
260 }
261 _mosquitto_free(config->bridges[i].addresses);
262 }
263 if(config->bridges[i].clientid) _mosquitto_free(config->bridges[i].clientid);
264 if(config->bridges[i].username) _mosquitto_free(config->bridges[i].username);
265 if(config->bridges[i].password) _mosquitto_free(config->bridges[i].password);
266 if(config->bridges[i].topics){
267 for(j=0; j<config->bridges[i].topic_count; j++){
268 if(config->bridges[i].topics[j].topic) _mosquitto_free(config->bridges[i].topics[j].topic);
269 if(config->bridges[i].topics[j].local_prefix) _mosquitto_free(config->bridges[i].topics[j].local_prefix);
270 if(config->bridges[i].topics[j].remote_prefix) _mosquitto_free(config->bridges[i].topics[j].remote_prefix);
271 if(config->bridges[i].topics[j].local_topic) _mosquitto_free(config->bridges[i].topics[j].local_topic);
272 if(config->bridges[i].topics[j].remote_topic) _mosquitto_free(config->bridges[i].topics[j].remote_topic);
273 }
274 _mosquitto_free(config->bridges[i].topics);
275 }
276 if(config->bridges[i].notification_topic) _mosquitto_free(config->bridges[i].notification_topic);
277#ifdef REAL_WITH_TLS_PSK
278 if(config->bridges[i].tls_psk_identity) _mosquitto_free(config->bridges[i].tls_psk_identity);
279 if(config->bridges[i].tls_psk) _mosquitto_free(config->bridges[i].tls_psk);
280#endif
281 }
282 _mosquitto_free(config->bridges);
283 }
284#endif
285 if(config->auth_plugin) _mosquitto_free(config->auth_plugin);
286 if(config->auth_options){
287 for(i=0; i<config->auth_option_count; i++){
288 _mosquitto_free(config->auth_options[i].key);
289 _mosquitto_free(config->auth_options[i].value);
290 }
291 _mosquitto_free(config->auth_options);
292 config->auth_options = NULL;
293 config->auth_option_count = 0;
294 }
295 if(config->log_fptr){
296 fclose(config->log_fptr);
297 config->log_fptr = NULL;
298 }
299 if(config->log_file){
300 _mosquitto_free(config->log_file);
301 config->log_file = NULL;
302 }
303}
304
305static void print_usage(void)
306{
307 printf("mosquitto version %s (build date %s)\n\n", VERSION, TIMESTAMP);
308 printf("mosquitto is an MQTT v3.1 broker.\n\n");
309 printf("Usage: mosquitto [-c config_file] [-d] [-h] [-p port]\n\n");
310 printf(" -c : specify the broker config file.\n");
311 printf(" -d : put the broker into the background after starting.\n");
312 printf(" -h : display this help.\n");
313 printf(" -p : start the broker listening on the specified port.\n");
314 printf(" Not recommended in conjunction with the -c option.\n");
315 printf(" -v : verbose mode - enable all logging types. This overrides\n");
316 printf(" any logging options given in the config file.\n");
317 printf("\nSee http://mosquitto.org/ for more information.\n\n");
318}
319
320int mqtt3_config_parse_args(struct mqtt3_config *config, int argc, char *argv[])
321{
322 int i;
323 int port_tmp;
324
325 for(i=1; i<argc; i++){
326 if(!strcmp(argv[i], "-c") || !strcmp(argv[i], "--config-file")){
327 if(i<argc-1){
328 config->config_file = _mosquitto_strdup(argv[i+1]);
329 if(!config->config_file){
330 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
331 return MOSQ_ERR_NOMEM;
332 }
333
334 if(mqtt3_config_read(config, false)){
335 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open configuration file.");
336 return MOSQ_ERR_INVAL;
337 }
338 }else{
339 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: -c argument given, but no config file specified.");
340 return MOSQ_ERR_INVAL;
341 }
342 i++;
343 }else if(!strcmp(argv[i], "-d") || !strcmp(argv[i], "--daemon")){
344 config->daemon = true;
345 }else if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")){
346 print_usage();
347 return MOSQ_ERR_INVAL;
348 }else if(!strcmp(argv[i], "-p") || !strcmp(argv[i], "--port")){
349 if(i<argc-1){
350 port_tmp = atoi(argv[i+1]);
351 if(port_tmp<1 || port_tmp>65535){
352 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid port specified (%d).", port_tmp);
353 return MOSQ_ERR_INVAL;
354 }else{
355 if(config->default_listener.port){
356 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Default listener port specified multiple times. Only the latest will be used.");
357 }
358 config->default_listener.port = port_tmp;
359 }
360 }else{
361 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: -p argument given, but no port specified.");
362 return MOSQ_ERR_INVAL;
363 }
364 i++;
365 }else if(!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")){
366 config->verbose = true;
367 }else{
368 fprintf(stderr, "Error: Unknown option '%s'.\n",argv[i]);
369 print_usage();
370 return MOSQ_ERR_INVAL;
371 }
372 }
373
374 if(config->listener_count == 0
375#ifdef WITH_TLS
376 || config->default_listener.cafile
377 || config->default_listener.capath
378 || config->default_listener.certfile
379 || config->default_listener.keyfile
380 || config->default_listener.ciphers
381 || config->default_listener.psk_hint
382 || config->default_listener.require_certificate
383 || config->default_listener.crlfile
384 || config->default_listener.use_identity_as_username
385#endif
386 || config->default_listener.host
387 || config->default_listener.port
388 || config->default_listener.max_connections != -1
389 || config->default_listener.mount_point){
390
391 config->listener_count++;
392 config->listeners = _mosquitto_realloc(config->listeners, sizeof(struct _mqtt3_listener)*config->listener_count);
393 if(!config->listeners){
394 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
395 return MOSQ_ERR_NOMEM;
396 }
397 if(config->default_listener.port){
398 config->listeners[config->listener_count-1].port = config->default_listener.port;
399 }else{
400 config->listeners[config->listener_count-1].port = 1883;
401 }
402 if(config->default_listener.host){
403 config->listeners[config->listener_count-1].host = config->default_listener.host;
404 }else{
405 config->listeners[config->listener_count-1].host = NULL;
406 }
407 if(config->default_listener.mount_point){
408 config->listeners[config->listener_count-1].mount_point = config->default_listener.mount_point;
409 }else{
410 config->listeners[config->listener_count-1].mount_point = NULL;
411 }
412 config->listeners[config->listener_count-1].max_connections = config->default_listener.max_connections;
413 config->listeners[config->listener_count-1].client_count = 0;
414 config->listeners[config->listener_count-1].socks = NULL;
415 config->listeners[config->listener_count-1].sock_count = 0;
416 config->listeners[config->listener_count-1].client_count = 0;
417#ifdef WITH_TLS
418 config->listeners[config->listener_count-1].tls_version = config->default_listener.tls_version;
419 config->listeners[config->listener_count-1].cafile = config->default_listener.cafile;
420 config->listeners[config->listener_count-1].capath = config->default_listener.capath;
421 config->listeners[config->listener_count-1].certfile = config->default_listener.certfile;
422 config->listeners[config->listener_count-1].keyfile = config->default_listener.keyfile;
423 config->listeners[config->listener_count-1].ciphers = config->default_listener.ciphers;
424 config->listeners[config->listener_count-1].psk_hint = config->default_listener.psk_hint;
425 config->listeners[config->listener_count-1].require_certificate = config->default_listener.require_certificate;
426 config->listeners[config->listener_count-1].ssl_ctx = NULL;
427 config->listeners[config->listener_count-1].crlfile = config->default_listener.crlfile;
428 config->listeners[config->listener_count-1].use_identity_as_username = config->default_listener.use_identity_as_username;
429#endif
430 }
431
432 /* Default to drop to mosquitto user if we are privileged and no user specified. */
433 if(!config->user){
434 config->user = "mosquitto";
435 }
436 if(config->verbose){
437 config->log_type = INT_MAX;
438 }
439 return MOSQ_ERR_SUCCESS;
440}
441
442int mqtt3_config_read(struct mqtt3_config *config, bool reload)
443{
444 int rc = MOSQ_ERR_SUCCESS;
445 struct config_recurse cr;
446 int lineno;
447#ifdef WITH_BRIDGE
448 int i;
449#endif
450
451 cr.log_dest = MQTT3_LOG_NONE;
452 cr.log_dest_set = 0;
453 cr.log_type = MOSQ_LOG_NONE;
454 cr.log_type_set = 0;
455 cr.max_inflight_messages = 20;
456 cr.max_queued_messages = 100;
457
458 if(!config->config_file) return 0;
459
460 if(reload){
461 /* Re-initialise appropriate config vars to default for reload. */
462 _config_init_reload(config);
463 }
464 rc = _config_read_file(config, reload, config->config_file, &cr, 0, &lineno);
465 if(rc){
466 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error found at %s:%d.", config->config_file, lineno);
467 return rc;
468 }
469
470#ifdef WITH_PERSISTENCE
471 if(config->persistence){
472 if(!config->persistence_file){
473 config->persistence_file = _mosquitto_strdup("mosquitto.db");
474 if(!config->persistence_file) return MOSQ_ERR_NOMEM;
475 }
476 if(config->persistence_filepath){
477 _mosquitto_free(config->persistence_filepath);
478 }
479 if(config->persistence_location && strlen(config->persistence_location)){
480 config->persistence_filepath = _mosquitto_malloc(strlen(config->persistence_location) + strlen(config->persistence_file) + 1);
481 if(!config->persistence_filepath) return MOSQ_ERR_NOMEM;
482 sprintf(config->persistence_filepath, "%s%s", config->persistence_location, config->persistence_file);
483 }else{
484 config->persistence_filepath = _mosquitto_strdup(config->persistence_file);
485 if(!config->persistence_filepath) return MOSQ_ERR_NOMEM;
486 }
487 }
488#endif
489 /* Default to drop to mosquitto user if no other user specified. This must
490 * remain here even though it is covered in mqtt3_parse_args() because this
491 * function may be called on its own. */
492 if(!config->user){
493 config->user = "mosquitto";
494 }
495
496 mqtt3_db_limits_set(cr.max_inflight_messages, cr.max_queued_messages);
497
498#ifdef WITH_BRIDGE
499 for(i=0; i<config->bridge_count; i++){
500 if(!config->bridges[i].name || !config->bridges[i].addresses || !config->bridges[i].topic_count){
501 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
502 return MOSQ_ERR_INVAL;
503 }
504#ifdef REAL_WITH_TLS_PSK
505 if(config->bridges[i].tls_psk && !config->bridges[i].tls_psk_identity){
506 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration: missing bridge_identity.\n");
507 return MOSQ_ERR_INVAL;
508 }
509 if(config->bridges[i].tls_psk_identity && !config->bridges[i].tls_psk){
510 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration: missing bridge_psk.\n");
511 return MOSQ_ERR_INVAL;
512 }
513#endif
514 }
515#endif
516
517 if(cr.log_dest_set){
518 config->log_dest = cr.log_dest;
519 }
520 if(config->verbose){
521 config->log_type = MOSQ_LOG_DEBUG | MOSQ_LOG_ERR | MOSQ_LOG_WARNING | MOSQ_LOG_NOTICE | MOSQ_LOG_INFO;
522 }else if(cr.log_type_set){
523 config->log_type = cr.log_type;
524 }
525 return MOSQ_ERR_SUCCESS;
526}
527
528int _config_read_file(struct mqtt3_config *config, bool reload, const char *file, struct config_recurse *cr, int level, int *lineno)
529{
530 int rc;
531 FILE *fptr = NULL;
532 char buf[1024];
533 char *token;
534 int port_tmp;
535 char *saveptr = NULL;
536#ifdef WITH_BRIDGE
537 struct _mqtt3_bridge *cur_bridge = NULL;
538 struct _mqtt3_bridge_topic *cur_topic;
539#endif
540 time_t expiration_mult;
541 char *key;
542 char *conf_file;
543#ifdef WIN32
544 HANDLE fh;
545 char dirpath[MAX_PATH];
546 WIN32_FIND_DATA find_data;
547#else
548 DIR *dh;
549 struct dirent *de;
550#endif
551 int len;
552 struct _mqtt3_listener *cur_listener = &config->default_listener;
553#ifdef WITH_BRIDGE
554 char *address;
555 int i;
556#endif
557 int lineno_ext;
558
559 fptr = _mosquitto_fopen(file, "rt");
560 if(!fptr){
561 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open config file %s\n", file);
562 return 1;
563 }
564
565 *lineno = 0;
566
567 while(fgets(buf, 1024, fptr)){
568 (*lineno)++;
569 if(buf[0] != '#' && buf[0] != 10 && buf[0] != 13){
570 while(buf[strlen(buf)-1] == 10 || buf[strlen(buf)-1] == 13){
571 buf[strlen(buf)-1] = 0;
572 }
573 token = strtok_r(buf, " ", &saveptr);
574 if(token){
575 if(!strcmp(token, "acl_file")){
576 if(reload){
577 if(config->acl_file){
578 _mosquitto_free(config->acl_file);
579 config->acl_file = NULL;
580 }
581 }
582 if(_conf_parse_string(&token, "acl_file", &config->acl_file, saveptr)) return MOSQ_ERR_INVAL;
583 }else if(!strcmp(token, "address") || !strcmp(token, "addresses")){
584#ifdef WITH_BRIDGE
585 if(reload) continue; // FIXME
586 if(!cur_bridge || cur_bridge->addresses){
587 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
588 return MOSQ_ERR_INVAL;
589 }
590 while((token = strtok_r(NULL, " ", &saveptr))){
591 cur_bridge->address_count++;
592 cur_bridge->addresses = _mosquitto_realloc(cur_bridge->addresses, sizeof(struct bridge_address)*cur_bridge->address_count);
593 if(!cur_bridge->addresses){
594 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
595 return MOSQ_ERR_NOMEM;
596 }
597 cur_bridge->addresses[cur_bridge->address_count-1].address = token;
598 }
599 for(i=0; i<cur_bridge->address_count; i++){
600 address = strtok_r(cur_bridge->addresses[i].address, ":", &saveptr);
601 if(address){
602 token = strtok_r(NULL, ":", &saveptr);
603 if(token){
604 port_tmp = atoi(token);
605 if(port_tmp < 1 || port_tmp > 65535){
606 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid port value (%d).", port_tmp);
607 return MOSQ_ERR_INVAL;
608 }
609 cur_bridge->addresses[i].port = port_tmp;
610 }else{
611 cur_bridge->addresses[i].port = 1883;
612 }
613 cur_bridge->addresses[i].address = _mosquitto_strdup(address);
614 _conf_attempt_resolve(address, "bridge address", MOSQ_LOG_WARNING, "Warning");
615 }
616 }
617 if(cur_bridge->address_count == 0){
618 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty address value in configuration.");
619 return MOSQ_ERR_INVAL;
620 }
621#else
622 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available.");
623#endif
624 }else if(!strcmp(token, "allow_anonymous")){
625 if(_conf_parse_bool(&token, "allow_anonymous", &config->allow_anonymous, saveptr)) return MOSQ_ERR_INVAL;
626 }else if(!strcmp(token, "allow_duplicate_messages")){
627 if(_conf_parse_bool(&token, "allow_duplicate_messages", &config->allow_duplicate_messages, saveptr)) return MOSQ_ERR_INVAL;
628 }else if(!strcmp(token, "allow_zero_length_clientid")){
629 if(_conf_parse_bool(&token, "allow_zero_length_clientid", &config->allow_zero_length_clientid, saveptr)) return MOSQ_ERR_INVAL;
630 }else if(!strncmp(token, "auth_opt_", 9)){
631 if(strlen(token) < 12){
632 /* auth_opt_ == 9, + one digit key == 10, + one space == 11, + one value == 12 */
633 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid auth_opt_ config option.");
634 return MOSQ_ERR_INVAL;
635 }
636 key = _mosquitto_strdup(&token[9]);
637 if(!key){
638 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
639 return MOSQ_ERR_NOMEM;
640 }else if(strlen(key) == 0){
641 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid auth_opt_ config option.");
642 return MOSQ_ERR_INVAL;
643 }
644 token += 9+strlen(key)+1;
645 if(token[0]){
646 config->auth_option_count++;
647 config->auth_options = _mosquitto_realloc(config->auth_options, config->auth_option_count*sizeof(struct mosquitto_auth_opt));
648 if(!config->auth_options){
649 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
650 return MOSQ_ERR_NOMEM;
651 }
652 config->auth_options[config->auth_option_count-1].key = key;
653 config->auth_options[config->auth_option_count-1].value = _mosquitto_strdup(token);
654 if(!config->auth_options[config->auth_option_count-1].value){
655 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
656 return MOSQ_ERR_NOMEM;
657 }
658 }else{
659 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty %s value in configuration.", key);
660 return MOSQ_ERR_INVAL;
661 }
662 }else if(!strcmp(token, "auth_plugin")){
663 if(reload) continue; // Auth plugin not currently valid for reloading.
664 if(_conf_parse_string(&token, "auth_plugin", &config->auth_plugin, saveptr)) return MOSQ_ERR_INVAL;
665 }else if(!strcmp(token, "auto_id_prefix")){
666 if(_conf_parse_string(&token, "auto_id_prefix", &config->auto_id_prefix, saveptr)) return MOSQ_ERR_INVAL;
667 if(config->auto_id_prefix){
668 config->auto_id_prefix_len = strlen(config->auto_id_prefix);
669 }else{
670 config->auto_id_prefix_len = 0;
671 }
672 }else if(!strcmp(token, "autosave_interval")){
673 if(_conf_parse_int(&token, "autosave_interval", &config->autosave_interval, saveptr)) return MOSQ_ERR_INVAL;
674 if(config->autosave_interval < 0) config->autosave_interval = 0;
675 }else if(!strcmp(token, "autosave_on_changes")){
676 if(_conf_parse_bool(&token, "autosave_on_changes", &config->autosave_on_changes, saveptr)) return MOSQ_ERR_INVAL;
677 }else if(!strcmp(token, "bind_address")){
678 if(reload) continue; // Listener not valid for reloading.
679 if(_conf_parse_string(&token, "default listener bind_address", &config->default_listener.host, saveptr)) return MOSQ_ERR_INVAL;
680 if(_conf_attempt_resolve(config->default_listener.host, "bind_address", MOSQ_LOG_ERR, "Error")){
681 return MOSQ_ERR_INVAL;
682 }
683 }else if(!strcmp(token, "bridge_cafile")){
684#if defined(WITH_BRIDGE) && defined(WITH_TLS)
685 if(reload) continue; // FIXME
686 if(!cur_bridge){
687 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
688 return MOSQ_ERR_INVAL;
689 }
690#ifdef REAL_WITH_TLS_PSK
691 if(cur_bridge->tls_psk_identity || cur_bridge->tls_psk){
692 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Cannot use both certificate and psk encryption in a single bridge.");
693 return MOSQ_ERR_INVAL;
694 }
695#endif
696 token = strtok_r(NULL, " ", &saveptr);
697 if(token){
698 if(cur_bridge->tls_cafile){
699 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Duplicate bridge_cafile value in bridge configuration.");
700 return MOSQ_ERR_INVAL;
701 }
702 cur_bridge->tls_cafile = _mosquitto_strdup(token);
703 if(!cur_bridge->tls_cafile){
704 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
705 return MOSQ_ERR_NOMEM;
706 }
707 }else{
708 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty bridge_cafile value in configuration.");
709 return MOSQ_ERR_INVAL;
710 }
711#else
712 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge and/or TLS support not available.");
713#endif
714 }else if(!strcmp(token, "bridge_capath")){
715#if defined(WITH_BRIDGE) && defined(WITH_TLS)
716 if(reload) continue; // FIXME
717 if(!cur_bridge){
718 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
719 return MOSQ_ERR_INVAL;
720 }
721#ifdef REAL_WITH_TLS_PSK
722 if(cur_bridge->tls_psk_identity || cur_bridge->tls_psk){
723 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Cannot use both certificate and psk encryption in a single bridge.");
724 return MOSQ_ERR_INVAL;
725 }
726#endif
727 token = strtok_r(NULL, " ", &saveptr);
728 if(token){
729 if(cur_bridge->tls_capath){
730 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Duplicate bridge_capath value in bridge configuration.");
731 return MOSQ_ERR_INVAL;
732 }
733 cur_bridge->tls_capath = _mosquitto_strdup(token);
734 if(!cur_bridge->tls_capath){
735 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
736 return MOSQ_ERR_NOMEM;
737 }
738 }else{
739 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty bridge_capath value in configuration.");
740 return MOSQ_ERR_INVAL;
741 }
742#else
743 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge and/or TLS support not available.");
744#endif
745 }else if(!strcmp(token, "bridge_certfile")){
746#if defined(WITH_BRIDGE) && defined(WITH_TLS)
747 if(reload) continue; // FIXME
748 if(!cur_bridge){
749 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
750 return MOSQ_ERR_INVAL;
751 }
752#ifdef REAL_WITH_TLS_PSK
753 if(cur_bridge->tls_psk_identity || cur_bridge->tls_psk){
754 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Cannot use both certificate and psk encryption in a single bridge.");
755 return MOSQ_ERR_INVAL;
756 }
757#endif
758 token = strtok_r(NULL, " ", &saveptr);
759 if(token){
760 if(cur_bridge->tls_certfile){
761 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Duplicate bridge_certfile value in bridge configuration.");
762 return MOSQ_ERR_INVAL;
763 }
764 cur_bridge->tls_certfile = _mosquitto_strdup(token);
765 if(!cur_bridge->tls_certfile){
766 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
767 return MOSQ_ERR_NOMEM;
768 }
769 }else{
770 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty bridge_certfile value in configuration.");
771 return MOSQ_ERR_INVAL;
772 }
773#else
774 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge and/or TLS support not available.");
775#endif
776 }else if(!strcmp(token, "bridge_identity")){
777#if defined(WITH_BRIDGE) && defined(REAL_WITH_TLS_PSK)
778 if(reload) continue; // FIXME
779 if(!cur_bridge){
780 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
781 return MOSQ_ERR_INVAL;
782 }
783 if(cur_bridge->tls_cafile || cur_bridge->tls_capath || cur_bridge->tls_certfile || cur_bridge->tls_keyfile){
784 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Cannot use both certificate and identity encryption in a single bridge.");
785 return MOSQ_ERR_INVAL;
786 }
787 token = strtok_r(NULL, " ", &saveptr);
788 if(token){
789 if(cur_bridge->tls_psk_identity){
790 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Duplicate bridge_identity value in bridge configuration.");
791 return MOSQ_ERR_INVAL;
792 }
793 cur_bridge->tls_psk_identity = _mosquitto_strdup(token);
794 if(!cur_bridge->tls_psk_identity){
795 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
796 return MOSQ_ERR_NOMEM;
797 }
798 }else{
799 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty bridge_identity value in configuration.");
800 return MOSQ_ERR_INVAL;
801 }
802#else
803 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge and/or TLS-PSK support not available.");
804#endif
805 }else if(!strcmp(token, "bridge_insecure")){
806#if defined(WITH_BRIDGE) && defined(WITH_TLS)
807 if(reload) continue; // FIXME
808 if(!cur_bridge){
809 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
810 return MOSQ_ERR_INVAL;
811 }
812 if(_conf_parse_bool(&token, "bridge_insecure", &cur_bridge->tls_insecure, saveptr)) return MOSQ_ERR_INVAL;
813 if(cur_bridge->tls_insecure){
814 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge %s using insecure mode.", cur_bridge->name);
815 }
816#else
817 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge and/or TLS-PSK support not available.");
818#endif
819 }else if(!strcmp(token, "bridge_keyfile")){
820#if defined(WITH_BRIDGE) && defined(WITH_TLS)
821 if(reload) continue; // FIXME
822 if(!cur_bridge){
823 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
824 return MOSQ_ERR_INVAL;
825 }
826#ifdef REAL_WITH_TLS_PSK
827 if(cur_bridge->tls_psk_identity || cur_bridge->tls_psk){
828 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Cannot use both certificate and psk encryption in a single bridge.");
829 return MOSQ_ERR_INVAL;
830 }
831#endif
832 token = strtok_r(NULL, " ", &saveptr);
833 if(token){
834 if(cur_bridge->tls_keyfile){
835 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Duplicate bridge_keyfile value in bridge configuration.");
836 return MOSQ_ERR_INVAL;
837 }
838 cur_bridge->tls_keyfile = _mosquitto_strdup(token);
839 if(!cur_bridge->tls_keyfile){
840 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
841 return MOSQ_ERR_NOMEM;
842 }
843 }else{
844 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty bridge_keyfile value in configuration.");
845 return MOSQ_ERR_INVAL;
846 }
847#else
848 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge and/or TLS support not available.");
849#endif
850 }else if(!strcmp(token, "bridge_psk")){
851#if defined(WITH_BRIDGE) && defined(REAL_WITH_TLS_PSK)
852 if(reload) continue; // FIXME
853 if(!cur_bridge){
854 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
855 return MOSQ_ERR_INVAL;
856 }
857 if(cur_bridge->tls_cafile || cur_bridge->tls_capath || cur_bridge->tls_certfile || cur_bridge->tls_keyfile){
858 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Cannot use both certificate and psk encryption in a single bridge.");
859 return MOSQ_ERR_INVAL;
860 }
861 token = strtok_r(NULL, " ", &saveptr);
862 if(token){
863 if(cur_bridge->tls_psk){
864 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Duplicate bridge_psk value in bridge configuration.");
865 return MOSQ_ERR_INVAL;
866 }
867 cur_bridge->tls_psk = _mosquitto_strdup(token);
868 if(!cur_bridge->tls_psk){
869 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
870 return MOSQ_ERR_NOMEM;
871 }
872 }else{
873 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty bridge_psk value in configuration.");
874 return MOSQ_ERR_INVAL;
875 }
876#else
877 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge and/or TLS-PSK support not available.");
878#endif
879 }else if(!strcmp(token, "bridge_tls_version")){
880#if defined(WITH_BRIDGE) && defined(WITH_TLS)
881 if(reload) continue; // FIXME
882 if(!cur_bridge){
883 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
884 return MOSQ_ERR_INVAL;
885 }
886 token = strtok_r(NULL, " ", &saveptr);
887 if(token){
888 if(cur_bridge->tls_version){
889 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Duplicate bridge_tls_version value in bridge configuration.");
890 return MOSQ_ERR_INVAL;
891 }
892 cur_bridge->tls_version = _mosquitto_strdup(token);
893 if(!cur_bridge->tls_version){
894 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
895 return MOSQ_ERR_NOMEM;
896 }
897 }else{
898 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty bridge_tls_version value in configuration.");
899 return MOSQ_ERR_INVAL;
900 }
901#else
902 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge and/or TLS support not available.");
903#endif
904 }else if(!strcmp(token, "cafile")){
905#if defined(WITH_TLS)
906 if(reload) continue; // Listeners not valid for reloading.
907 if(cur_listener->psk_hint){
908 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Cannot use both certificate and psk encryption in a single listener.");
909 return MOSQ_ERR_INVAL;
910 }
911 if(_conf_parse_string(&token, "cafile", &cur_listener->cafile, saveptr)) return MOSQ_ERR_INVAL;
912#else
913 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS support not available.");
914#endif
915 }else if(!strcmp(token, "capath")){
916#ifdef WITH_TLS
917 if(reload) continue; // Listeners not valid for reloading.
918 if(_conf_parse_string(&token, "capath", &cur_listener->capath, saveptr)) return MOSQ_ERR_INVAL;
919#else
920 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS support not available.");
921#endif
922 }else if(!strcmp(token, "certfile")){
923#ifdef WITH_TLS
924 if(reload) continue; // Listeners not valid for reloading.
925 if(cur_listener->psk_hint){
926 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Cannot use both certificate and psk encryption in a single listener.");
927 return MOSQ_ERR_INVAL;
928 }
929 if(_conf_parse_string(&token, "certfile", &cur_listener->certfile, saveptr)) return MOSQ_ERR_INVAL;
930#else
931 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS support not available.");
932#endif
933 }else if(!strcmp(token, "ciphers")){
934#ifdef WITH_TLS
935 if(reload) continue; // Listeners not valid for reloading.
936 if(_conf_parse_string(&token, "ciphers", &cur_listener->ciphers, saveptr)) return MOSQ_ERR_INVAL;
937#else
938 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS support not available.");
939#endif
940 }else if(!strcmp(token, "clientid")){
941#ifdef WITH_BRIDGE
942 if(reload) continue; // FIXME
943 if(!cur_bridge){
944 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
945 return MOSQ_ERR_INVAL;
946 }
947 token = strtok_r(NULL, " ", &saveptr);
948 if(token){
949 if(cur_bridge->clientid){
950 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Duplicate clientid value in bridge configuration.");
951 return MOSQ_ERR_INVAL;
952 }
953 cur_bridge->clientid = _mosquitto_strdup(token);
954 if(!cur_bridge->clientid){
955 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
956 return MOSQ_ERR_NOMEM;
957 }
958 }else{
959 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty clientid value in configuration.");
960 return MOSQ_ERR_INVAL;
961 }
962#else
963 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available.");
964#endif
965 }else if(!strcmp(token, "cleansession")){
966#ifdef WITH_BRIDGE
967 if(reload) continue; // FIXME
968 if(!cur_bridge){
969 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
970 return MOSQ_ERR_INVAL;
971 }
972 if(_conf_parse_bool(&token, "cleansession", &cur_bridge->clean_session, saveptr)) return MOSQ_ERR_INVAL;
973#else
974 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available.");
975#endif
976 }else if(!strcmp(token, "clientid_prefixes")){
977 if(reload){
978 if(config->clientid_prefixes){
979 _mosquitto_free(config->clientid_prefixes);
980 config->clientid_prefixes = NULL;
981 }
982 }
983 if(_conf_parse_string(&token, "clientid_prefixes", &config->clientid_prefixes, saveptr)) return MOSQ_ERR_INVAL;
984 }else if(!strcmp(token, "connection")){
985#ifdef WITH_BRIDGE
986 if(reload) continue; // FIXME
987 token = strtok_r(NULL, " ", &saveptr);
988 if(token){
989 config->bridge_count++;
990 config->bridges = _mosquitto_realloc(config->bridges, config->bridge_count*sizeof(struct _mqtt3_bridge));
991 if(!config->bridges){
992 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
993 return MOSQ_ERR_NOMEM;
994 }
995 cur_bridge = &(config->bridges[config->bridge_count-1]);
996 memset(cur_bridge, 0, sizeof(struct _mqtt3_bridge));
997 cur_bridge->name = _mosquitto_strdup(token);
998 if(!cur_bridge->name){
999 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
1000 return MOSQ_ERR_NOMEM;
1001 }
1002 cur_bridge->keepalive = 60;
1003 cur_bridge->notifications = true;
1004 cur_bridge->start_type = bst_automatic;
1005 cur_bridge->idle_timeout = 60;
1006 cur_bridge->restart_timeout = 30;
1007 cur_bridge->threshold = 10;
1008 cur_bridge->try_private = true;
1009 }else{
1010 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty connection value in configuration.");
1011 return MOSQ_ERR_INVAL;
1012 }
1013#else
1014 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available.");
1015#endif
1016 }else if(!strcmp(token, "connection_messages")){
1017 if(_conf_parse_bool(&token, token, &config->connection_messages, saveptr)) return MOSQ_ERR_INVAL;
1018 }else if(!strcmp(token, "crlfile")){
1019#ifdef WITH_TLS
1020 if(reload) continue; // Listeners not valid for reloading.
1021 if(_conf_parse_string(&token, "crlfile", &cur_listener->crlfile, saveptr)) return MOSQ_ERR_INVAL;
1022#else
1023 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS support not available.");
1024#endif
1025 }else if(!strcmp(token, "idle_timeout")){
1026#ifdef WITH_BRIDGE
1027 if(reload) continue; // FIXME
1028 if(!cur_bridge){
1029 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
1030 return MOSQ_ERR_INVAL;
1031 }
1032 if(_conf_parse_int(&token, "idle_timeout", &cur_bridge->idle_timeout, saveptr)) return MOSQ_ERR_INVAL;
1033 if(cur_bridge->idle_timeout < 1){
1034 _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "idle_timeout interval too low, using 1 second.");
1035 cur_bridge->idle_timeout = 1;
1036 }
1037#else
1038 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available.");
1039#endif
1040 }else if(!strcmp(token, "include_dir")){
1041 if(level == 0){
1042 /* Only process include_dir from the main config file. */
1043 token = strtok_r(NULL, " ", &saveptr);
1044 if(!token){
1045 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty include_dir value in configuration.");
1046 }
1047#ifdef WIN32
1048 snprintf(dirpath, MAX_PATH, "%s\\*.conf", token);
1049 fh = FindFirstFile(dirpath, &find_data);
1050 if(fh == INVALID_HANDLE_VALUE){
1051 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open include_dir '%s'.", token);
1052 return 1;
1053 }
1054
1055 do{
1056 len = strlen(token)+1+strlen(find_data.cFileName)+1;
1057 conf_file = _mosquitto_calloc(len+1, sizeof(char));
1058 if(!conf_file){
1059 FindClose(fh);
1060 return MOSQ_ERR_NOMEM;
1061 }
1062 snprintf(conf_file, len, "%s\\%s", token, find_data.cFileName);
1063
1064 rc = _config_read_file(config, reload, conf_file, cr, level+1, &lineno_ext);
1065 if(rc){
1066 FindClose(fh);
1067 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error found at %s:%d.", conf_file, lineno_ext);
1068 _mosquitto_free(conf_file);
1069 return rc;
1070 }
1071 _mosquitto_free(conf_file);
1072 }while(FindNextFile(fh, &find_data));
1073
1074 FindClose(fh);
1075#else
1076 dh = opendir(token);
1077 if(!dh){
1078 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open include_dir '%s'.", token);
1079 return 1;
1080 }
1081 while((de = readdir(dh)) != NULL){
1082 if(strlen(de->d_name) > 5){
1083 if(!strcmp(&de->d_name[strlen(de->d_name)-5], ".conf")){
1084 len = strlen(token)+1+strlen(de->d_name)+1;
1085 conf_file = _mosquitto_calloc(len+1, sizeof(char));
1086 if(!conf_file){
1087 closedir(dh);
1088 return MOSQ_ERR_NOMEM;
1089 }
1090 snprintf(conf_file, len, "%s/%s", token, de->d_name);
1091
1092 rc = _config_read_file(config, reload, conf_file, cr, level+1, &lineno_ext);
1093 if(rc){
1094 closedir(dh);
1095 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error found at %s:%d.", conf_file, lineno_ext);
1096 _mosquitto_free(conf_file);
1097 return rc;
1098 }
1099 _mosquitto_free(conf_file);
1100 }
1101 }
1102 }
1103 closedir(dh);
1104#endif
1105 }
1106 }else if(!strcmp(token, "keepalive_interval")){
1107#ifdef WITH_BRIDGE
1108 if(reload) continue; // FIXME
1109 if(!cur_bridge){
1110 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
1111 return MOSQ_ERR_INVAL;
1112 }
1113 if(_conf_parse_int(&token, "keepalive_interval", &cur_bridge->keepalive, saveptr)) return MOSQ_ERR_INVAL;
1114 if(cur_bridge->keepalive < 5){
1115 _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "keepalive interval too low, using 5 seconds.");
1116 cur_bridge->keepalive = 5;
1117 }
1118#else
1119 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available.");
1120#endif
1121 }else if(!strcmp(token, "keyfile")){
1122#ifdef WITH_TLS
1123 if(reload) continue; // Listeners not valid for reloading.
1124 if(_conf_parse_string(&token, "keyfile", &cur_listener->keyfile, saveptr)) return MOSQ_ERR_INVAL;
1125#else
1126 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS support not available.");
1127#endif
1128 }else if(!strcmp(token, "listener")){
1129 if(reload) continue; // Listeners not valid for reloading.
1130 token = strtok_r(NULL, " ", &saveptr);
1131 if(token){
1132 config->listener_count++;
1133 config->listeners = _mosquitto_realloc(config->listeners, sizeof(struct _mqtt3_listener)*config->listener_count);
1134 if(!config->listeners){
1135 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
1136 return MOSQ_ERR_NOMEM;
1137 }
1138 port_tmp = atoi(token);
1139 if(port_tmp < 1 || port_tmp > 65535){
1140 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid port value (%d).", port_tmp);
1141 return MOSQ_ERR_INVAL;
1142 }
1143 cur_listener = &config->listeners[config->listener_count-1];
1144 memset(cur_listener, 0, sizeof(struct _mqtt3_listener));
1145 cur_listener->port = port_tmp;
1146 token = strtok_r(NULL, " ", &saveptr);
1147 if(token){
1148 cur_listener->host = _mosquitto_strdup(token);
1149 }else{
1150 cur_listener->host = NULL;
1151 }
1152 }else{
1153 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty listener value in configuration.");
1154 return MOSQ_ERR_INVAL;
1155 }
1156 }else if(!strcmp(token, "log_dest")){
1157 token = strtok_r(NULL, " ", &saveptr);
1158 if(token){
1159 cr->log_dest_set = 1;
1160 if(!strcmp(token, "none")){
1161 cr->log_dest = MQTT3_LOG_NONE;
1162 }else if(!strcmp(token, "syslog")){
1163 cr->log_dest |= MQTT3_LOG_SYSLOG;
1164 }else if(!strcmp(token, "stdout")){
1165 cr->log_dest |= MQTT3_LOG_STDOUT;
1166 }else if(!strcmp(token, "stderr")){
1167 cr->log_dest |= MQTT3_LOG_STDERR;
1168 }else if(!strcmp(token, "topic")){
1169 cr->log_dest |= MQTT3_LOG_TOPIC;
1170 }else if(!strcmp(token, "file")){
1171 cr->log_dest |= MQTT3_LOG_FILE;
1172 if(config->log_fptr || config->log_file){
1173 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Duplicate \"log_dest file\" value.");
1174 return MOSQ_ERR_INVAL;
1175 }
1176 /* Get remaining string. */
1177 token = &token[strlen(token)+1];
1178 while(token[0] == ' '){
1179 token++;
1180 }
1181 if(token[0]){
1182 config->log_file = _mosquitto_strdup(token);
1183 if(!config->log_file){
1184 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
1185 return MOSQ_ERR_NOMEM;
1186 }
1187 config->log_fptr = _mosquitto_fopen(config->log_file, "at");
1188 if(!config->log_fptr){
1189 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open log file %s for writing.", config->log_file);
1190 return MOSQ_ERR_INVAL;
1191 }
1192 }else{
1193 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty \"log_dest file\" value in configuration.");
1194 return MOSQ_ERR_INVAL;
1195 }
1196 }else{
1197 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid log_dest value (%s).", token);
1198 return MOSQ_ERR_INVAL;
1199 }
1200#if defined(WIN32) || defined(__CYGWIN__)
1201 if(service_handle){
1202 if(cr->log_dest == MQTT3_LOG_STDOUT || cr->log_dest == MQTT3_LOG_STDERR){
1203 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Cannot log to stdout/stderr when running as a Windows service.");
1204 return MOSQ_ERR_INVAL;
1205 }
1206 }
1207#endif
1208 }else{
1209 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty log_dest value in configuration.");
1210 return MOSQ_ERR_INVAL;
1211 }
1212 }else if(!strcmp(token, "log_timestamp")){
1213 if(_conf_parse_bool(&token, token, &config->log_timestamp, saveptr)) return MOSQ_ERR_INVAL;
1214 }else if(!strcmp(token, "log_type")){
1215 token = strtok_r(NULL, " ", &saveptr);
1216 if(token){
1217 cr->log_type_set = 1;
1218 if(!strcmp(token, "none")){
1219 cr->log_type = MOSQ_LOG_NONE;
1220 }else if(!strcmp(token, "information")){
1221 cr->log_type |= MOSQ_LOG_INFO;
1222 }else if(!strcmp(token, "notice")){
1223 cr->log_type |= MOSQ_LOG_NOTICE;
1224 }else if(!strcmp(token, "warning")){
1225 cr->log_type |= MOSQ_LOG_WARNING;
1226 }else if(!strcmp(token, "error")){
1227 cr->log_type |= MOSQ_LOG_ERR;
1228 }else if(!strcmp(token, "debug")){
1229 cr->log_type |= MOSQ_LOG_DEBUG;
1230 }else if(!strcmp(token, "subscribe")){
1231 cr->log_type |= MOSQ_LOG_SUBSCRIBE;
1232 }else if(!strcmp(token, "unsubscribe")){
1233 cr->log_type |= MOSQ_LOG_UNSUBSCRIBE;
1234 }else if(!strcmp(token, "all")){
1235 cr->log_type = INT_MAX;
1236 }else{
1237 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid log_type value (%s).", token);
1238 return MOSQ_ERR_INVAL;
1239 }
1240 }else{
1241 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty log_type value in configuration.");
1242 }
1243 }else if(!strcmp(token, "max_connections")){
1244 if(reload) continue; // Listeners not valid for reloading.
1245 token = strtok_r(NULL, " ", &saveptr);
1246 if(token){
1247 cur_listener->max_connections = atoi(token);
1248 if(cur_listener->max_connections < 0) cur_listener->max_connections = -1;
1249 }else{
1250 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty max_connections value in configuration.");
1251 }
1252 }else if(!strcmp(token, "max_inflight_messages")){
1253 token = strtok_r(NULL, " ", &saveptr);
1254 if(token){
1255 cr->max_inflight_messages = atoi(token);
1256 if(cr->max_inflight_messages < 0) cr->max_inflight_messages = 0;
1257 }else{
1258 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty max_inflight_messages value in configuration.");
1259 }
1260 }else if(!strcmp(token, "max_queued_messages")){
1261 token = strtok_r(NULL, " ", &saveptr);
1262 if(token){
1263 cr->max_queued_messages = atoi(token);
1264 if(cr->max_queued_messages < 0) cr->max_queued_messages = 0;
1265 }else{
1266 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty max_queued_messages value in configuration.");
1267 }
1268 }else if(!strcmp(token, "message_size_limit")){
1269 if(_conf_parse_int(&token, "message_size_limit", &config->message_size_limit, saveptr)) return MOSQ_ERR_INVAL;
1270 if(config->message_size_limit < 0 || config->message_size_limit > MQTT_MAX_PAYLOAD){
1271 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid message_size_limit value (%d).", config->message_size_limit);
1272 return MOSQ_ERR_INVAL;
1273 }
1274 }else if(!strcmp(token, "mount_point")){
1275 if(reload) continue; // Listeners not valid for reloading.
1276 if(config->listener_count == 0){
1277 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: You must use create a listener before using the mount_point option in the configuration file.");
1278 return MOSQ_ERR_INVAL;
1279 }
1280 if(_conf_parse_string(&token, "mount_point", &cur_listener->mount_point, saveptr)) return MOSQ_ERR_INVAL;
1281 if(_mosquitto_topic_wildcard_len_check(cur_listener->mount_point) != MOSQ_ERR_SUCCESS){
1282 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR,
1283 "Error: Invalid mount_point '%s'. Does it contain a wildcard character?",
1284 cur_listener->mount_point);
1285 return MOSQ_ERR_INVAL;
1286 }
1287 }else if(!strcmp(token, "notifications")){
1288#ifdef WITH_BRIDGE
1289 if(reload) continue; // FIXME
1290 if(!cur_bridge){
1291 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
1292 return MOSQ_ERR_INVAL;
1293 }
1294 if(_conf_parse_bool(&token, "notifications", &cur_bridge->notifications, saveptr)) return MOSQ_ERR_INVAL;
1295#else
1296 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available.");
1297#endif
1298 }else if(!strcmp(token, "notification_topic")){
1299#ifdef WITH_BRIDGE
1300 if(reload) continue; // FIXME
1301 if(!cur_bridge){
1302 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
1303 return MOSQ_ERR_INVAL;
1304 }
1305 if(_conf_parse_string(&token, "notification_topic", &cur_bridge->notification_topic, saveptr)) return MOSQ_ERR_INVAL;
1306#else
1307 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available.");
1308#endif
1309 }else if(!strcmp(token, "password")){
1310#ifdef WITH_BRIDGE
1311 if(reload) continue; // FIXME
1312 if(!cur_bridge){
1313 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
1314 return MOSQ_ERR_INVAL;
1315 }
1316 token = strtok_r(NULL, " ", &saveptr);
1317 if(token){
1318 if(cur_bridge->password){
1319 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Duplicate password value in bridge configuration.");
1320 return MOSQ_ERR_INVAL;
1321 }
1322 cur_bridge->password = _mosquitto_strdup(token);
1323 if(!cur_bridge->password){
1324 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
1325 return MOSQ_ERR_NOMEM;
1326 }
1327 }else{
1328 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty password value in configuration.");
1329 return MOSQ_ERR_INVAL;
1330 }
1331#else
1332 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available.");
1333#endif
1334 }else if(!strcmp(token, "password_file")){
1335 if(reload){
1336 if(config->password_file){
1337 _mosquitto_free(config->password_file);
1338 config->password_file = NULL;
1339 }
1340 }
1341 if(_conf_parse_string(&token, "password_file", &config->password_file, saveptr)) return MOSQ_ERR_INVAL;
1342 }else if(!strcmp(token, "persistence") || !strcmp(token, "retained_persistence")){
1343 if(_conf_parse_bool(&token, token, &config->persistence, saveptr)) return MOSQ_ERR_INVAL;
1344 }else if(!strcmp(token, "persistence_file")){
1345 if(_conf_parse_string(&token, "persistence_file", &config->persistence_file, saveptr)) return MOSQ_ERR_INVAL;
1346 }else if(!strcmp(token, "persistence_location")){
1347 if(_conf_parse_string(&token, "persistence_location", &config->persistence_location, saveptr)) return MOSQ_ERR_INVAL;
1348 }else if(!strcmp(token, "persistent_client_expiration")){
1349 token = strtok_r(NULL, " ", &saveptr);
1350 if(token){
1351 switch(token[strlen(token)-1]){
1352 case 'd':
1353 expiration_mult = 86400;
1354 break;
1355 case 'w':
1356 expiration_mult = 86400*7;
1357 break;
1358 case 'm':
1359 expiration_mult = 86400*30;
1360 break;
1361 case 'y':
1362 expiration_mult = 86400*365;
1363 break;
1364 default:
1365 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid persistent_client_expiration duration in configuration.");
1366 return MOSQ_ERR_INVAL;
1367 }
1368 token[strlen(token)-1] = '\0';
1369 config->persistent_client_expiration = atoi(token)*expiration_mult;
1370 if(config->persistent_client_expiration <= 0){
1371 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid persistent_client_expiration duration in configuration.");
1372 return MOSQ_ERR_INVAL;
1373 }
1374 }else{
1375 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty persistent_client_expiration value in configuration.");
1376 }
1377 }else if(!strcmp(token, "pid_file")){
1378 if(reload) continue; // pid file not valid for reloading.
1379 if(_conf_parse_string(&token, "pid_file", &config->pid_file, saveptr)) return MOSQ_ERR_INVAL;
1380 }else if(!strcmp(token, "port")){
1381 if(reload) continue; // Listener not valid for reloading.
1382 if(config->default_listener.port){
1383 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Default listener port specified multiple times. Only the latest will be used.");
1384 }
1385 if(_conf_parse_int(&token, "port", &port_tmp, saveptr)) return MOSQ_ERR_INVAL;
1386 if(port_tmp < 1 || port_tmp > 65535){
1387 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid port value (%d).", port_tmp);
1388 return MOSQ_ERR_INVAL;
1389 }
1390 config->default_listener.port = port_tmp;
1391 }else if(!strcmp(token, "psk_file")){
1392#ifdef REAL_WITH_TLS_PSK
1393 if(reload){
1394 if(config->psk_file){
1395 _mosquitto_free(config->psk_file);
1396 config->psk_file = NULL;
1397 }
1398 }
1399 if(_conf_parse_string(&token, "psk_file", &config->psk_file, saveptr)) return MOSQ_ERR_INVAL;
1400#else
1401 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS/TLS-PSK support not available.");
1402#endif
1403 }else if(!strcmp(token, "psk_hint")){
1404#ifdef REAL_WITH_TLS_PSK
1405 if(reload) continue; // Listeners not valid for reloading.
1406 if(_conf_parse_string(&token, "psk_hint", &cur_listener->psk_hint, saveptr)) return MOSQ_ERR_INVAL;
1407#else
1408 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS/TLS-PSK support not available.");
1409#endif
1410 }else if(!strcmp(token, "queue_qos0_messages")){
1411 if(_conf_parse_bool(&token, token, &config->queue_qos0_messages, saveptr)) return MOSQ_ERR_INVAL;
1412 }else if(!strcmp(token, "require_certificate")){
1413#ifdef WITH_TLS
1414 if(reload) continue; // Listeners not valid for reloading.
1415 if(_conf_parse_bool(&token, "require_certificate", &cur_listener->require_certificate, saveptr)) return MOSQ_ERR_INVAL;
1416#else
1417 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS support not available.");
1418#endif
1419 }else if(!strcmp(token, "restart_timeout")){
1420#ifdef WITH_BRIDGE
1421 if(reload) continue; // FIXME
1422 if(!cur_bridge){
1423 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
1424 return MOSQ_ERR_INVAL;
1425 }
1426 if(_conf_parse_int(&token, "restart_timeout", &cur_bridge->restart_timeout, saveptr)) return MOSQ_ERR_INVAL;
1427 if(cur_bridge->restart_timeout < 1){
1428 _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "restart_timeout interval too low, using 1 second.");
1429 cur_bridge->restart_timeout = 1;
1430 }
1431#else
1432 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available.");
1433#endif
1434 }else if(!strcmp(token, "retry_interval")){
1435 if(_conf_parse_int(&token, "retry_interval", &config->retry_interval, saveptr)) return MOSQ_ERR_INVAL;
1436 if(config->retry_interval < 1 || config->retry_interval > 3600){
1437 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid retry_interval value (%d).", config->retry_interval);
1438 return MOSQ_ERR_INVAL;
1439 }
1440 }else if(!strcmp(token, "round_robin")){
1441#ifdef WITH_BRIDGE
1442 if(reload) continue; // FIXME
1443 if(!cur_bridge){
1444 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
1445 return MOSQ_ERR_INVAL;
1446 }
1447 if(_conf_parse_bool(&token, "round_robin", &cur_bridge->round_robin, saveptr)) return MOSQ_ERR_INVAL;
1448#else
1449 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available.");
1450#endif
1451 }else if(!strcmp(token, "start_type")){
1452#ifdef WITH_BRIDGE
1453 if(reload) continue; // FIXME
1454 if(!cur_bridge){
1455 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
1456 return MOSQ_ERR_INVAL;
1457 }
1458 token = strtok_r(NULL, " ", &saveptr);
1459 if(token){
1460 if(!strcmp(token, "automatic")){
1461 cur_bridge->start_type = bst_automatic;
1462 }else if(!strcmp(token, "lazy")){
1463 cur_bridge->start_type = bst_lazy;
1464 }else if(!strcmp(token, "manual")){
1465 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Manual start_type not supported.");
1466 return MOSQ_ERR_INVAL;
1467 }else if(!strcmp(token, "once")){
1468 cur_bridge->start_type = bst_once;
1469 }else{
1470 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid start_type value in configuration (%s).", token);
1471 return MOSQ_ERR_INVAL;
1472 }
1473 }else{
1474 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty start_type value in configuration.");
1475 return MOSQ_ERR_INVAL;
1476 }
1477#else
1478 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available.");
1479#endif
1480 }else if(!strcmp(token, "store_clean_interval")){
1481 if(_conf_parse_int(&token, "store_clean_interval", &config->store_clean_interval, saveptr)) return MOSQ_ERR_INVAL;
1482 if(config->store_clean_interval < 0 || config->store_clean_interval > 65535){
1483 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid store_clean_interval value (%d).", config->store_clean_interval);
1484 return MOSQ_ERR_INVAL;
1485 }
1486 }else if(!strcmp(token, "sys_interval")){
1487 if(_conf_parse_int(&token, "sys_interval", &config->sys_interval, saveptr)) return MOSQ_ERR_INVAL;
1488 if(config->sys_interval < 0 || config->sys_interval > 65535){
1489 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid sys_interval value (%d).", config->sys_interval);
1490 return MOSQ_ERR_INVAL;
1491 }
1492 }else if(!strcmp(token, "threshold")){
1493#ifdef WITH_BRIDGE
1494 if(reload) continue; // FIXME
1495 if(!cur_bridge){
1496 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
1497 return MOSQ_ERR_INVAL;
1498 }
1499 if(_conf_parse_int(&token, "threshold", &cur_bridge->threshold, saveptr)) return MOSQ_ERR_INVAL;
1500 if(cur_bridge->threshold < 1){
1501 _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "threshold too low, using 1 message.");
1502 cur_bridge->threshold = 1;
1503 }
1504#else
1505 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available.");
1506#endif
1507 }else if(!strcmp(token, "tls_version")){
1508#if defined(WITH_TLS)
1509 if(reload) continue; // Listeners not valid for reloading.
1510 if(_conf_parse_string(&token, "tls_version", &cur_listener->tls_version, saveptr)) return MOSQ_ERR_INVAL;
1511#else
1512 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS support not available.");
1513#endif
1514 }else if(!strcmp(token, "topic")){
1515#ifdef WITH_BRIDGE
1516 if(reload) continue; // FIXME
1517 if(!cur_bridge){
1518 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
1519 return MOSQ_ERR_INVAL;
1520 }
1521 token = strtok_r(NULL, " ", &saveptr);
1522 if(token){
1523 cur_bridge->topic_count++;
1524 cur_bridge->topics = _mosquitto_realloc(cur_bridge->topics,
1525 sizeof(struct _mqtt3_bridge_topic)*cur_bridge->topic_count);
1526 if(!cur_bridge->topics){
1527 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
1528 return MOSQ_ERR_NOMEM;
1529 }
1530 cur_topic = &cur_bridge->topics[cur_bridge->topic_count-1];
1531 if(!strcmp(token, "\"\"")){
1532 cur_topic->topic = NULL;
1533 }else{
1534 cur_topic->topic = _mosquitto_strdup(token);
1535 if(!cur_topic->topic){
1536 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
1537 return MOSQ_ERR_NOMEM;
1538 }
1539 }
1540 cur_topic->direction = bd_out;
1541 cur_topic->qos = 0;
1542 cur_topic->local_prefix = NULL;
1543 cur_topic->remote_prefix = NULL;
1544 }else{
1545 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty topic value in configuration.");
1546 return MOSQ_ERR_INVAL;
1547 }
1548 token = strtok_r(NULL, " ", &saveptr);
1549 if(token){
1550 if(!strcasecmp(token, "out")){
1551 cur_topic->direction = bd_out;
1552 }else if(!strcasecmp(token, "in")){
1553 cur_topic->direction = bd_in;
1554 }else if(!strcasecmp(token, "both")){
1555 cur_topic->direction = bd_both;
1556 }else{
1557 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge topic direction '%s'.", token);
1558 return MOSQ_ERR_INVAL;
1559 }
1560 token = strtok_r(NULL, " ", &saveptr);
1561 if(token){
1562 cur_topic->qos = atoi(token);
1563 if(cur_topic->qos < 0 || cur_topic->qos > 2){
1564 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge QoS level '%s'.", token);
1565 return MOSQ_ERR_INVAL;
1566 }
1567
1568 token = strtok_r(NULL, " ", &saveptr);
1569 if(token){
1570 cur_bridge->topic_remapping = true;
1571 if(!strcmp(token, "\"\"")){
1572 cur_topic->local_prefix = NULL;
1573 }else{
1574 if(_mosquitto_topic_wildcard_len_check(token) != MOSQ_ERR_SUCCESS){
1575 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge topic local prefix '%s'.", token);
1576 return MOSQ_ERR_INVAL;
1577 }
1578 cur_topic->local_prefix = _mosquitto_strdup(token);
1579 if(!cur_topic->local_prefix){
1580 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
1581 return MOSQ_ERR_NOMEM;
1582 }
1583 }
1584
1585 token = strtok_r(NULL, " ", &saveptr);
1586 if(token){
1587 if(!strcmp(token, "\"\"")){
1588 cur_topic->remote_prefix = NULL;
1589 }else{
1590 if(_mosquitto_topic_wildcard_len_check(token) != MOSQ_ERR_SUCCESS){
1591 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge topic remote prefix '%s'.", token);
1592 return MOSQ_ERR_INVAL;
1593 }
1594 cur_topic->remote_prefix = _mosquitto_strdup(token);
1595 if(!cur_topic->remote_prefix){
1596 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
1597 return MOSQ_ERR_NOMEM;
1598 }
1599 }
1600 }
1601 }
1602 }
1603 }
1604 if(cur_topic->topic == NULL &&
1605 (cur_topic->local_prefix == NULL || cur_topic->remote_prefix == NULL)){
1606
1607 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge remapping.");
1608 return MOSQ_ERR_INVAL;
1609 }
1610 if(cur_topic->local_prefix){
1611 if(cur_topic->topic){
1612 len = strlen(cur_topic->topic) + strlen(cur_topic->local_prefix)+1;
1613 cur_topic->local_topic = _mosquitto_calloc(len+1, sizeof(char));
1614 if(!cur_topic->local_topic){
1615 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
1616 return MOSQ_ERR_NOMEM;
1617 }
1618 snprintf(cur_topic->local_topic, len+1, "%s%s", cur_topic->local_prefix, cur_topic->topic);
1619 }else{
1620 cur_topic->local_topic = _mosquitto_strdup(cur_topic->local_prefix);
1621 if(!cur_topic->local_topic){
1622 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
1623 return MOSQ_ERR_NOMEM;
1624 }
1625 }
1626 }else{
1627 cur_topic->local_topic = _mosquitto_strdup(cur_topic->topic);
1628 if(!cur_topic->local_topic){
1629 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
1630 return MOSQ_ERR_NOMEM;
1631 }
1632 }
1633
1634 if(cur_topic->remote_prefix){
1635 if(cur_topic->topic){
1636 len = strlen(cur_topic->topic) + strlen(cur_topic->remote_prefix)+1;
1637 cur_topic->remote_topic = _mosquitto_calloc(len+1, sizeof(char));
1638 if(!cur_topic->remote_topic){
1639 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
1640 return MOSQ_ERR_NOMEM;
1641 }
1642 snprintf(cur_topic->remote_topic, len, "%s%s", cur_topic->remote_prefix, cur_topic->topic);
1643 }else{
1644 cur_topic->remote_topic = _mosquitto_strdup(cur_topic->remote_prefix);
1645 if(!cur_topic->remote_topic){
1646 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
1647 return MOSQ_ERR_NOMEM;
1648 }
1649 }
1650 }else{
1651 cur_topic->remote_topic = _mosquitto_strdup(cur_topic->topic);
1652 if(!cur_topic->remote_topic){
1653 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
1654 return MOSQ_ERR_NOMEM;
1655 }
1656 }
1657#else
1658 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available.");
1659#endif
1660 }else if(!strcmp(token, "try_private")){
1661#ifdef WITH_BRIDGE
1662 if(reload) continue; // FIXME
1663 if(!cur_bridge){
1664 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
1665 return MOSQ_ERR_INVAL;
1666 }
1667 if(_conf_parse_bool(&token, "try_private", &cur_bridge->try_private, saveptr)) return MOSQ_ERR_INVAL;
1668#else
1669 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available.");
1670#endif
1671 }else if(!strcmp(token, "upgrade_outgoing_qos")){
1672 if(_conf_parse_bool(&token, token, &config->upgrade_outgoing_qos, saveptr)) return MOSQ_ERR_INVAL;
1673 }else if(!strcmp(token, "use_identity_as_username")){
1674#ifdef WITH_TLS
1675 if(reload) continue; // Listeners not valid for reloading.
1676 if(_conf_parse_bool(&token, "use_identity_as_username", &cur_listener->use_identity_as_username, saveptr)) return MOSQ_ERR_INVAL;
1677#else
1678 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS support not available.");
1679#endif
1680 }else if(!strcmp(token, "user")){
1681 if(reload) continue; // Drop privileges user not valid for reloading.
1682 if(_conf_parse_string(&token, "user", &config->user, saveptr)) return MOSQ_ERR_INVAL;
1683 }else if(!strcmp(token, "username")){
1684#ifdef WITH_BRIDGE
1685 if(reload) continue; // FIXME
1686 if(!cur_bridge){
1687 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
1688 return MOSQ_ERR_INVAL;
1689 }
1690 token = strtok_r(NULL, " ", &saveptr);
1691 if(token){
1692 if(cur_bridge->username){
1693 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Duplicate username value in bridge configuration.");
1694 return MOSQ_ERR_INVAL;
1695 }
1696 cur_bridge->username = _mosquitto_strdup(token);
1697 if(!cur_bridge->username){
1698 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
1699 return MOSQ_ERR_NOMEM;
1700 }
1701 }else{
1702 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty username value in configuration.");
1703 return MOSQ_ERR_INVAL;
1704 }
1705#else
1706 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available.");
1707#endif
1708 }else if(!strcmp(token, "trace_level")
1709 || !strcmp(token, "ffdc_output")
1710 || !strcmp(token, "max_log_entries")
1711 || !strcmp(token, "trace_output")){
1712 _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Unsupported rsmb configuration option \"%s\".", token);
1713 }else{
1714 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unknown configuration variable \"%s\".", token);
1715 return MOSQ_ERR_INVAL;
1716 }
1717 }
1718 }
1719 }
1720 fclose(fptr);
1721
1722 return MOSQ_ERR_SUCCESS;
1723}
1724
1725static int _conf_parse_bool(char **token, const char *name, bool *value, char *saveptr)
1726{
1727 *token = strtok_r(NULL, " ", &saveptr);
1728 if(*token){
1729 if(!strcmp(*token, "false") || !strcmp(*token, "0")){
1730 *value = false;
1731 }else if(!strcmp(*token, "true") || !strcmp(*token, "1")){
1732 *value = true;
1733 }else{
1734 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid %s value (%s).", name, *token);
1735 }
1736 }else{
1737 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty %s value in configuration.", name);
1738 return MOSQ_ERR_INVAL;
1739 }
1740
1741 return MOSQ_ERR_SUCCESS;
1742}
1743
1744static int _conf_parse_int(char **token, const char *name, int *value, char *saveptr)
1745{
1746 *token = strtok_r(NULL, " ", &saveptr);
1747 if(*token){
1748 *value = atoi(*token);
1749 }else{
1750 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty %s value in configuration.", name);
1751 return MOSQ_ERR_INVAL;
1752 }
1753
1754 return MOSQ_ERR_SUCCESS;
1755}
1756
1757static int _conf_parse_string(char **token, const char *name, char **value, char *saveptr)
1758{
1759 *token = strtok_r(NULL, " ", &saveptr);
1760 if(*token){
1761 if(*value){
1762 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Duplicate %s value in configuration.", name);
1763 return MOSQ_ERR_INVAL;
1764 }
1765 *value = _mosquitto_strdup(*token);
1766 if(!*value){
1767 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory");
1768 return MOSQ_ERR_NOMEM;
1769 }
1770 }else{
1771 _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty %s value in configuration.", name);
1772 return MOSQ_ERR_INVAL;
1773 }
1774 return MOSQ_ERR_SUCCESS;
1775}