Coverage Report

Created: 2025-11-07 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mosquitto/plugins/dynamic-security/plugin.c
Line
Count
Source
1
/*
2
Copyright (c) 2020-2021 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 <errno.h>
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <string.h>
25
#include <sys/stat.h>
26
27
#ifndef WIN32
28
#  include <strings.h>
29
#endif
30
31
#include "mosquitto.h"
32
33
#include "dynamic_security.h"
34
#include "json_help.h"
35
36
MOSQUITTO_PLUGIN_DECLARE_VERSION(5);
37
38
static struct dynsec__data dynsec_data;
39
static mosquitto_plugin_id_t *plg_id = NULL;
40
41
#ifdef WIN32
42
#  include <winsock2.h>
43
#  include <aclapi.h>
44
#  include <io.h>
45
#  include <lmcons.h>
46
#  include <fcntl.h>
47
#  define PATH_MAX MAX_PATH
48
#else
49
#  include <sys/stat.h>
50
#  include <pwd.h>
51
#  include <grp.h>
52
#  include <unistd.h>
53
#endif
54
55
56
int mosquitto_plugin_init(mosquitto_plugin_id_t *identifier, void **user_data, struct mosquitto_opt *options, int option_count)
57
5.78k
{
58
5.78k
  int i;
59
5.78k
  int rc;
60
61
5.78k
  UNUSED(user_data);
62
63
5.78k
  memset(&dynsec_data, 0, sizeof(struct dynsec__data));
64
65
11.5k
  for(i=0; i<option_count; i++){
66
5.78k
    if(!strcasecmp(options[i].key, "config_file")){
67
5.78k
      dynsec_data.config_file = mosquitto_strdup(options[i].value);
68
5.78k
      if(dynsec_data.config_file == NULL){
69
0
        return MOSQ_ERR_NOMEM;
70
0
      }
71
5.78k
    }else if(!strcasecmp(options[i].key, "password_init_file")){
72
0
      dynsec_data.password_init_file = mosquitto_strdup(options[i].value);
73
0
      if(dynsec_data.password_init_file == NULL){
74
0
        return MOSQ_ERR_NOMEM;
75
0
      }
76
0
    }
77
5.78k
  }
78
5.78k
  if(dynsec_data.config_file == NULL){
79
0
    mosquitto_log_printf(MOSQ_LOG_WARNING, "Warning: Dynamic security plugin has no plugin_opt_config_file defined. The plugin will not be activated.");
80
0
    return MOSQ_ERR_SUCCESS;
81
0
  }
82
83
5.78k
  plg_id = identifier;
84
5.78k
  mosquitto_plugin_set_info(identifier, "dynamic-security", NULL);
85
86
5.78k
  dynsec__config_load(&dynsec_data);
87
88
5.78k
  rc = mosquitto_callback_register(plg_id, MOSQ_EVT_CONTROL, dynsec_control_callback, "$CONTROL/dynamic-security/v1", &dynsec_data);
89
5.78k
  if(rc == MOSQ_ERR_ALREADY_EXISTS){
90
0
    mosquitto_log_printf(MOSQ_LOG_ERR, "Error: Dynamic security plugin can currently only be loaded once.");
91
0
    mosquitto_log_printf(MOSQ_LOG_ERR, "Note that this was previously incorrectly allowed but could cause problems with duplicate entries in the config.");
92
0
    goto error;
93
5.78k
  }else if(rc == MOSQ_ERR_NOMEM){
94
0
    mosquitto_log_printf(MOSQ_LOG_ERR, "Error: Out of memory.");
95
0
    goto error;
96
5.78k
  }else if(rc != MOSQ_ERR_SUCCESS){
97
0
    goto error;
98
0
  }
99
100
5.78k
  rc = mosquitto_callback_register(plg_id, MOSQ_EVT_BASIC_AUTH, dynsec_auth__basic_auth_callback, NULL, &dynsec_data);
101
5.78k
  if(rc == MOSQ_ERR_ALREADY_EXISTS){
102
0
    mosquitto_log_printf(MOSQ_LOG_ERR, "Error: Dynamic security plugin can only be loaded once.");
103
0
    goto error;
104
5.78k
  }else if(rc == MOSQ_ERR_NOMEM){
105
0
    mosquitto_log_printf(MOSQ_LOG_ERR, "Error: Out of memory.");
106
0
    goto error;
107
5.78k
  }else if(rc != MOSQ_ERR_SUCCESS){
108
5.78k
    goto error;
109
5.78k
  }
110
111
0
  rc = mosquitto_callback_register(plg_id, MOSQ_EVT_ACL_CHECK, dynsec__acl_check_callback, NULL, &dynsec_data);
112
0
  if(rc == MOSQ_ERR_ALREADY_EXISTS){
113
0
    mosquitto_log_printf(MOSQ_LOG_ERR, "Error: Dynamic security plugin can only be loaded once.");
114
0
    goto error;
115
0
  }else if(rc == MOSQ_ERR_NOMEM){
116
0
    mosquitto_log_printf(MOSQ_LOG_ERR, "Error: Out of memory.");
117
0
    goto error;
118
0
  }else if(rc != MOSQ_ERR_SUCCESS){
119
0
    goto error;
120
0
  }
121
122
0
  rc = mosquitto_callback_register(plg_id, MOSQ_EVT_TICK, dynsec__tick_callback, NULL, &dynsec_data);
123
0
  if(rc == MOSQ_ERR_NOMEM){
124
0
    mosquitto_log_printf(MOSQ_LOG_ERR, "Error: Out of memory.");
125
0
    goto error;
126
0
  }else if(rc != MOSQ_ERR_SUCCESS){
127
0
    goto error;
128
0
  }
129
130
0
  return MOSQ_ERR_SUCCESS;
131
5.78k
error:
132
5.78k
  mosquitto_free(dynsec_data.config_file);
133
5.78k
  dynsec_data.config_file = NULL;
134
5.78k
  return rc;
135
0
}
136
137
138
int mosquitto_plugin_cleanup(void *user_data, struct mosquitto_opt *options, int option_count)
139
5.78k
{
140
5.78k
  UNUSED(user_data);
141
5.78k
  UNUSED(options);
142
5.78k
  UNUSED(option_count);
143
144
5.78k
  dynsec_groups__cleanup(&dynsec_data);
145
5.78k
  dynsec_clients__cleanup(&dynsec_data);
146
5.78k
  dynsec_roles__cleanup(&dynsec_data);
147
5.78k
  dynsec_kicklist__cleanup(&dynsec_data);
148
149
5.78k
  mosquitto_free(dynsec_data.config_file);
150
5.78k
  dynsec_data.config_file = NULL;
151
152
5.78k
  mosquitto_free(dynsec_data.password_init_file);
153
5.78k
  dynsec_data.password_init_file = NULL;
154
155
5.78k
  mosquitto_callback_unregister(plg_id, MOSQ_EVT_CONTROL, dynsec_control_callback, "$CONTROL/dynamic-security/v1");
156
5.78k
  mosquitto_callback_unregister(plg_id, MOSQ_EVT_BASIC_AUTH, dynsec_auth__basic_auth_callback, NULL);
157
5.78k
  mosquitto_callback_unregister(plg_id, MOSQ_EVT_ACL_CHECK, dynsec__acl_check_callback, NULL);
158
5.78k
  mosquitto_callback_unregister(plg_id, MOSQ_EVT_TICK, dynsec__tick_callback, NULL);
159
160
5.78k
  return MOSQ_ERR_SUCCESS;
161
5.78k
}