Skip to content

Commit 5bc98a1

Browse files
committed
feat(mosq): Add support for basic MQTT authentication
Closes #919
1 parent 318bca1 commit 5bc98a1

File tree

5 files changed

+75
-1
lines changed

5 files changed

+75
-1
lines changed

components/mosquitto/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ if (CONFIG_MOSQ_ENABLE_SYS)
9090
endif()
9191
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
9292

93+
# Enable linker wrapping for mosquitto_unpwd_check to allow connection callback interception
94+
# without modifying upstream code
95+
target_link_options(${COMPONENT_LIB} PRIVATE "-Wl,--wrap=mosquitto_unpwd_check")
96+
9397
# Some mosquitto source unconditionally define `_GNU_SOURCE` which collides with IDF build system
9498
# producing warning: "_GNU_SOURCE" redefined
9599
# This workarounds this issue by undefining the macro for the selected files

components/mosquitto/api.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
| ---: | :--- |
1717
| struct | [**mosq\_broker\_config**](#struct-mosq_broker_config) <br>_Mosquitto configuration structure._ |
1818
| typedef void(\* | [**mosq\_message\_cb\_t**](#typedef-mosq_message_cb_t) <br> |
19+
| typedef int(\* | [**mosq\_connect\_cb\_t**](#typedef-mosq_connect_cb_t) <br> |
1920

2021
## Functions
2122

@@ -37,6 +38,8 @@ Variables:
3738

3839
- void(\* handle_message_cb <br>On message callback. If configured, user function is called whenever mosquitto processes a message.
3940

41+
- mosq\_connect\_cb\_t handle_connect_cb <br>On connect callback. If configured, user function is called whenever a client attempts to connect. The callback receives client_id, username, password, and password length. Return 0 to accept the connection, non-zero to reject it.
42+
4043
- const char \* host <br>Address on which the broker is listening for connections
4144

4245
- int port <br>Port number of the broker to listen to
@@ -49,6 +52,26 @@ Variables:
4952
typedef void(* mosq_message_cb_t) (char *client, char *topic, char *data, int len, int qos, int retain);
5053
```
5154
55+
### typedef `mosq_connect_cb_t`
56+
57+
```c
58+
typedef int(* mosq_connect_cb_t) (const char *client_id, const char *username, const char *password, int password_len);
59+
```
60+
61+
Callback function type for connection authentication. Called when a client attempts to connect to the broker.
62+
63+
**Parameters:**
64+
65+
* `client_id` Client identifier string. Will be an empty string if not provided.
66+
* `username` Username string, or NULL if no username was provided.
67+
* `password` Password string (binary data), or NULL if no password was provided.
68+
* `password_len` Length of the password in bytes. Note: If password contains null bytes, this may not reflect the full binary length as mosquitto stores passwords as null-terminated strings.
69+
70+
**Returns:**
71+
72+
* `0` to accept the connection
73+
* Non-zero to reject the connection (will result in CONNACK_REFUSED_NOT_AUTHORIZED)
74+
5275

5376
## Functions Documentation
5477

components/mosquitto/port/broker.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ void mosq_broker_stop(void)
102102
}
103103

104104
extern mosq_message_cb_t g_mosq_message_callback;
105+
extern mosq_connect_cb_t g_mosq_connect_callback;
105106

106107
int mosq_broker_run(struct mosq_broker_config *broker_config)
107108
{
@@ -130,6 +131,9 @@ int mosq_broker_run(struct mosq_broker_config *broker_config)
130131
if (broker_config->handle_message_cb) {
131132
g_mosq_message_callback = broker_config->handle_message_cb;
132133
}
134+
if (broker_config->handle_connect_cb) {
135+
g_mosq_connect_callback = broker_config->handle_connect_cb;
136+
}
133137

134138
db.config = &config;
135139

components/mosquitto/port/callbacks.c

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
*
44
* SPDX-License-Identifier: EPL-2.0
55
*
6-
* SPDX-FileContributor: 2024 Espressif Systems (Shanghai) CO LTD
6+
* SPDX-FileContributor: 2024-2025 Espressif Systems (Shanghai) CO LTD
77
*/
8+
#include <string.h>
89
#include "mosquitto_internal.h"
910
#include "mosquitto_broker.h"
1011
#include "memory_mosq.h"
@@ -16,6 +17,7 @@
1617
#include "mosq_broker.h"
1718

1819
mosq_message_cb_t g_mosq_message_callback = NULL;
20+
mosq_connect_cb_t g_mosq_connect_callback = NULL;
1921

2022
int mosquitto_callback_register(
2123
mosquitto_plugin_id_t *identifier,
@@ -51,3 +53,37 @@ int plugin__handle_message(struct mosquitto *context, struct mosquitto_msg_store
5153
}
5254
return MOSQ_ERR_SUCCESS;
5355
}
56+
57+
/* Wrapper function to intercept mosquitto_unpwd_check calls via linker wrapping */
58+
int __wrap_mosquitto_unpwd_check(struct mosquitto *context)
59+
{
60+
int rc;
61+
int password_len = 0;
62+
63+
/* Call user's connect callback if set */
64+
if (g_mosq_connect_callback) {
65+
/* Extract password length if password is present.
66+
* Note: MQTT passwords are binary data, but mosquitto stores them as null-terminated strings.
67+
* If password contains null bytes, strlen() will not return the full length.
68+
* This matches how mosquitto itself handles passwords in some security functions. */
69+
if (context->password) {
70+
password_len = (int)strlen(context->password);
71+
}
72+
73+
/* Call user callback */
74+
rc = g_mosq_connect_callback(
75+
context->id ? context->id : "",
76+
context->username ? context->username : NULL,
77+
context->password ? context->password : NULL,
78+
password_len
79+
);
80+
81+
/* If callback rejects (returns non-zero), return AUTH error immediately */
82+
if (rc != 0) {
83+
return MOSQ_ERR_AUTH;
84+
}
85+
}
86+
87+
/* Call the original function */
88+
return __real_mosquitto_unpwd_check(context);
89+
}

components/mosquitto/port/include/mosq_broker.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ extern "C" {
1414
struct mosquitto__config;
1515

1616
typedef void (*mosq_message_cb_t)(char *client, char *topic, char *data, int len, int qos, int retain);
17+
18+
typedef int (*mosq_connect_cb_t)(const char *client_id, const char *username, const char *password, int password_len);
1719
/**
1820
* @brief Mosquitto configuration structure
1921
*
@@ -33,6 +35,11 @@ struct mosq_broker_config {
3335
* On message callback. If configured, user function is called
3436
* whenever mosquitto processes a message.
3537
*/
38+
mosq_connect_cb_t handle_connect_cb; /*!< On connect callback. If configured, user function is called
39+
* whenever a client attempts to connect. The callback receives
40+
* client_id, username, password, and password length. Return 0 to
41+
* accept the connection, non-zero to reject it.
42+
*/
3643
};
3744

3845
/**

0 commit comments

Comments
 (0)