diff --git a/src/MQTTAsync.c b/src/MQTTAsync.c index 5ff29d02c..7beafdf52 100644 --- a/src/MQTTAsync.c +++ b/src/MQTTAsync.c @@ -952,7 +952,8 @@ int MQTTAsync_connect(MQTTAsync handle, const MQTTAsync_connectOptions* options) property.value.data.data = authData.authDataOut.data; property.value.data.len = authData.authDataOut.len; rc = MQTTProperties_add(m->connectProps, &property); - free(authData.authDataOut.data); + if(authData.authDataOut.data) + free(authData.authDataOut.data); if (rc) goto exit; } diff --git a/src/MQTTAsync.h b/src/MQTTAsync.h index 9cd4efb21..4ede23011 100644 --- a/src/MQTTAsync.h +++ b/src/MQTTAsync.h @@ -565,7 +565,8 @@ typedef struct * This is a callback function which will allow the client application to update the * connection data. * @param data The connection data which can be modified by the application. - * @return Return a zero or positive value to indicate sucess, a negative value on failure. + * @return a negative value to indicate not-authorized, a value of 0 to indicate success, + * a positive value to indicate continue. */ typedef int MQTTAsync_authHandle(void* context, MQTTAsync_authHandleData* data); diff --git a/src/MQTTAsyncUtils.c b/src/MQTTAsyncUtils.c index 326a93d45..00d177070 100644 --- a/src/MQTTAsyncUtils.c +++ b/src/MQTTAsyncUtils.c @@ -62,8 +62,8 @@ static int cmdMessageIDCompare(void* a, void* b); static void MQTTAsync_retry(void); static MQTTPacket* MQTTAsync_cycle(SOCKET* sock, unsigned long timeout, int* rc); static int MQTTAsync_connecting(MQTTAsyncs* m); -static enum MQTTReasonCodes MQTTAsync_processAuth(MQTTAsync_authHandle *func, void *context, - MQTTAsync_authHandleData *data); +static enum MQTTReasonCodes MQTTAsync_processAuth(MQTTAsyncs *m, int rc, + MQTTProperties *props, MQTTAsync_authHandleData *out); static int MQTTAsync_verifyAuthMethod(const char* authMethod, const char* data, int dataLen); @@ -2140,39 +2140,10 @@ thread_return_type WINAPI MQTTAsync_receiveThread(void* n) if (rc == MQTTASYNC_SUCCESS && m->c->authMethod) { MQTTAsync_authHandleData authHandleData = MQTTAsync_authHandleData_initializer; - MQTTProperty *authMethodProp = NULL; - char *authMethod = NULL; - int authMethodLen = 0; - MQTTProperty *authData = NULL; - - authMethodProp = MQTTProperties_getProperty(&connack->properties, - MQTTPROPERTY_CODE_AUTHENTICATION_METHOD); - if (authMethodProp) - { - authMethod = authMethodProp->value.data.data; - authMethodLen = authMethodProp->value.data.len; - } - - if ((connack->rc == 0 && authMethodProp == NULL) || - MQTTAsync_verifyAuthMethod(m->c->authMethod, authMethod, - authMethodLen) == 0) - { - authData = MQTTProperties_getProperty(&connack->properties, - MQTTPROPERTY_CODE_AUTHENTICATION_DATA); - - authHandleData.reasonCode = connack->rc; - if (authData && authMethod) - { - authHandleData.authDataIn.data = authData->value.data.data; - authHandleData.authDataIn.len = authData->value.data.len; - } - - rc = MQTTAsync_processAuth(m->auth_handle, - m->auth_handle_context, - &authHandleData); - } - else - rc = MQTTREASONCODE_BAD_AUTHENTICATION_METHOD; + rc = MQTTAsync_processAuth(m, connack->rc, &connack->properties, + &authHandleData); + if (authHandleData.authDataOut.data) + free(authHandleData.authDataOut.data); } if (rc == MQTTASYNC_SUCCESS) @@ -2412,50 +2383,16 @@ thread_return_type WINAPI MQTTAsync_receiveThread(void* n) { Auth *auth = (Auth *)pack; enum MQTTReasonCodes authrc = MQTTREASONCODE_SUCCESS; - MQTTProperty *authMethodProp = NULL; - MQTTProperty *authData = NULL; - char* authMethod = NULL; - int authMethodLen = 0; MQTTAsync_authHandleData authHandleData = MQTTAsync_authHandleData_initializer; - if (m->c->authMethod) - { - authMethodProp = MQTTProperties_getProperty(&auth->properties, - MQTTPROPERTY_CODE_AUTHENTICATION_METHOD); - if (authMethodProp) - { - authMethod = authMethodProp->value.data.data; - authMethodLen = authMethodProp->value.data.len; - } - - if ((auth->rc == 0 && authMethodProp == NULL) || - MQTTAsync_verifyAuthMethod(m->c->authMethod, authMethod, - authMethodLen) == 0) - { - authData = MQTTProperties_getProperty(&auth->properties, - MQTTPROPERTY_CODE_AUTHENTICATION_DATA); - - authHandleData.reasonCode = auth->rc; - if (authData && authMethod) - { - authHandleData.authDataIn.data = authData->value.data.data; - authHandleData.authDataIn.len = authData->value.data.len; - } - - authrc = MQTTAsync_processAuth(m->auth_handle, - m->auth_handle_context, - &authHandleData); - } - else - authrc = MQTTREASONCODE_BAD_AUTHENTICATION_METHOD; - } - else - authrc = MQTTREASONCODE_PROTOCOL_ERROR; + authrc = MQTTAsync_processAuth(m, auth->rc, &auth->properties, + &authHandleData); rc = MQTTProtocol_handleAuth(pack, m->c->net.socket, authrc, authHandleData.authDataOut.data, authHandleData.authDataOut.len); - free(authHandleData.authDataOut.data); + if (authHandleData.authDataOut.data) + free(authHandleData.authDataOut.data); if (authrc != MQTTREASONCODE_SUCCESS && authrc != MQTTREASONCODE_CONTINUE_AUTHENTICATION) nextOrClose(m, authrc, "Authentication failed"); @@ -3320,34 +3257,54 @@ int MQTTAsync_getNoBufferedMessages(MQTTAsyncs* m) } -enum MQTTReasonCodes MQTTAsync_processAuth(MQTTAsync_authHandle *func, void *context, - MQTTAsync_authHandleData *data) +enum MQTTReasonCodes MQTTAsync_processAuth(MQTTAsyncs *m, int rc, MQTTProperties *props, + MQTTAsync_authHandleData *out) { - int rc; + MQTTProperty *authMethodProp = NULL; + char *authMethodIn = NULL; + int authMethodInLen = 0; + MQTTProperty *authData = NULL; - if (func == NULL) - return MQTTREASONCODE_NOT_AUTHORIZED; - - rc = (*(func))(context, data); - if (rc < 0) - return MQTTREASONCODE_NOT_AUTHORIZED; + if (!m->c->authMethod) + { + return MQTTREASONCODE_PROTOCOL_ERROR; + } - if (rc > 0) - return MQTTREASONCODE_CONTINUE_AUTHENTICATION; + authMethodProp = MQTTProperties_getProperty(props, + MQTTPROPERTY_CODE_AUTHENTICATION_METHOD); + if (authMethodProp) + { + authMethodIn = authMethodProp->value.data.data; + authMethodInLen = authMethodProp->value.data.len; + } - return MQTTREASONCODE_SUCCESS; -} + if ((rc == 0 && authMethodProp == NULL) || + (m->c->authMethod && authMethodIn && authMethodInLen > 0 && + strlen(m->c->authMethod) == authMethodInLen && + memcmp(m->c->authMethod, authMethodIn, authMethodInLen) == 0)) + { + if (m->auth_handle == NULL) + return MQTTREASONCODE_NOT_AUTHORIZED; + authData = MQTTProperties_getProperty(props, + MQTTPROPERTY_CODE_AUTHENTICATION_DATA); -int MQTTAsync_verifyAuthMethod(const char *authMethod, const char *data, int dataLen) -{ - if (authMethod && data && dataLen > 0) - { - if (strlen(authMethod) == dataLen && memcmp(authMethod, data, dataLen) == 0) + out->reasonCode = rc; + if (authData && authMethodIn) { - return 0; + out->authDataIn.data = authData->value.data.data; + out->authDataIn.len = authData->value.data.len; } + + rc = (*(m->auth_handle))(m->auth_handle_context, out); + if (rc < 0) + return MQTTREASONCODE_NOT_AUTHORIZED; + + if (rc > 0) + return MQTTREASONCODE_CONTINUE_AUTHENTICATION; + + return MQTTREASONCODE_SUCCESS; } - return -1; + return MQTTREASONCODE_BAD_AUTHENTICATION_METHOD; } diff --git a/src/MQTTClient.c b/src/MQTTClient.c index 4781816eb..8d2f39cbb 100644 --- a/src/MQTTClient.c +++ b/src/MQTTClient.c @@ -361,6 +361,8 @@ static MQTTPacket* MQTTClient_waitfor(MQTTClient handle, int packet_type, int* r static void MQTTProtocol_checkPendingWrites(void); static void MQTTClient_writeComplete(SOCKET socket, int rc); static void MQTTClient_writeContinue(SOCKET socket); +static enum MQTTReasonCodes MQTTClient_processAuth(MQTTClients *m, int rc, + MQTTProperties *props, MQTTClient_handleAuthData *out); int MQTTClient_createWithOptions(MQTTClient* handle, const char* serverURI, const char* clientId, @@ -801,25 +803,6 @@ int MQTTClient_setHandleAuth(MQTTClient handle, void* context, MQTTClient_handle } -/** - * Wrapper function to call authHandle on a separate thread. A separate thread is needed to allow the - * disconnected function to make API calls (e.g. MQTTClient_auth) - * @param context a pointer to the relevant client - * @return thread_return_type standard thread return value - not used here - */ -static thread_return_type WINAPI call_auth_handle(void* context) -{ - struct props_rc_parms* pr = (struct props_rc_parms*)context; - - //(*(pr->m->auth_handle))(pr->m->auth_handle_context, pr->properties, pr->reasonCode); - abort(); //TODO: Implement for MQTTClient - MQTTProperties_free(pr->properties); - free(pr->properties); - free(pr); - return 0; -} - - /* This is the thread function that handles the calling of callback functions if set */ static thread_return_type WINAPI MQTTClient_run(void* n) { @@ -953,17 +936,23 @@ static thread_return_type WINAPI MQTTClient_run(void* n) } free(disc); } - else if (pack->header.bits.type == AUTH && m->auth_handle) + else if (pack->header.bits.type == AUTH) { - struct props_rc_parms dp; - Ack* disc = (Ack*)pack; - - dp.m = m; - dp.properties = &disc->properties; - dp.reasonCode = disc->rc; - free(pack); - Log(TRACE_MIN, -1, "Calling auth_handle for client %s", m->c->clientID); - Thread_start(call_auth_handle, &dp); + Auth *auth = (Auth *)pack; + enum MQTTReasonCodes authrc = MQTTREASONCODE_SUCCESS; + MQTTClient_handleAuthData authHandleData = MQTTClient_handleAuthData_initializer; + + authrc = MQTTClient_processAuth(m, auth->rc, &auth->properties, + &authHandleData); + + rc = MQTTProtocol_handleAuth(pack, m->c->net.socket, authrc, + authHandleData.authDataOut.data, + authHandleData.authDataOut.len); + if (authHandleData.authDataOut.data) + free(authHandleData.authDataOut.data); + if (authrc != MQTTREASONCODE_SUCCESS && + authrc != MQTTREASONCODE_CONTINUE_AUTHENTICATION) + MQTTClient_disconnect_internal(m, 0); } } } @@ -1421,7 +1410,18 @@ static MQTTResponse MQTTClient_connectURIVersion(MQTTClient handle, MQTTClient_c { Connack* connack = (Connack*)pack; Log(TRACE_PROTOCOL, 1, NULL, m->c->net.socket, m->c->clientID, connack->rc); - if ((rc = connack->rc) == MQTTCLIENT_SUCCESS) + rc = connack->rc; + + if (rc == MQTTCLIENT_SUCCESS && m->c->authMethod) + { + MQTTClient_handleAuthData authHandleData = MQTTClient_handleAuthData_initializer; + rc = MQTTClient_processAuth(m, connack->rc, &connack->properties, + &authHandleData); + if (authHandleData.authDataOut.data) + free(authHandleData.authDataOut.data); + } + + if (rc == MQTTCLIENT_SUCCESS) { m->c->connected = 1; m->c->good = 1; @@ -1724,7 +1724,8 @@ static MQTTResponse MQTTClient_connectURI(MQTTClient handle, MQTTClient_connectO property.value.data.data = authData.authDataOut.data; property.value.data.len = authData.authDataOut.len; rc.reasonCode = MQTTProperties_add(connectProperties, &property); - free(authData.authDataOut.data); + if (authData.authDataOut.data) + free(authData.authDataOut.data); if (rc.reasonCode) goto exit; } @@ -3258,6 +3259,54 @@ int MQTTClient_setSelectInterface(MQTTClient handle, void* context, MQTTClient_s return rc; } +enum MQTTReasonCodes MQTTClient_processAuth(MQTTClients *m, int rc, MQTTProperties *props, + MQTTClient_handleAuthData *out) +{ + MQTTProperty *authMethodProp = NULL; + char *authMethodIn = NULL; + int authMethodInLen = 0; + MQTTProperty *authData = NULL; + + if (!m->c->authMethod) + { + return MQTTREASONCODE_PROTOCOL_ERROR; + } + + authMethodProp = MQTTProperties_getProperty(props, + MQTTPROPERTY_CODE_AUTHENTICATION_METHOD); + if (authMethodProp) + { + authMethodIn = authMethodProp->value.data.data; + authMethodInLen = authMethodProp->value.data.len; + } + + if ((rc == 0 && authMethodProp == NULL) || + (m->c->authMethod && authMethodIn && authMethodInLen > 0 && + strlen(m->c->authMethod) == authMethodInLen && + memcmp(m->c->authMethod, authMethodIn, authMethodInLen) == 0)) + { + if (m->auth_handle == NULL) + return MQTTREASONCODE_NOT_AUTHORIZED; + + authData = MQTTProperties_getProperty(props, + MQTTPROPERTY_CODE_AUTHENTICATION_DATA); + out->reasonCode = rc; + if (authData && authMethodIn) + { + out->authDataIn.data = authData->value.data.data; + out->authDataIn.len = authData->value.data.len; + } + rc = (*(m->auth_handle))(m->auth_handle_context, out); + if (rc < 0) + return MQTTREASONCODE_NOT_AUTHORIZED; + if (rc > 0) + return MQTTREASONCODE_CONTINUE_AUTHENTICATION; + + return MQTTREASONCODE_SUCCESS; + } + + return MQTTREASONCODE_BAD_AUTHENTICATION_METHOD; +} diff --git a/src/MQTTClient.h b/src/MQTTClient.h index 2e3c2b8fb..b6ae2fc53 100644 --- a/src/MQTTClient.h +++ b/src/MQTTClient.h @@ -523,10 +523,14 @@ typedef struct /** * This is a callback function, which will be called when a MQTTv5 enhanced * authentication packet is either received from the server or needs to be - * populated by the client. This applies to MQTT V5 and above only. + * populated by the client, it applies to MQTT V5 and above only. + * The callback is not executed on a dedicated thread, do not call other MQTTClient + * functions inside of it. * @param context A pointer to the context value originally passed to * ::MQTTClient_setHandleAuth(), which contains any application-specific context. * @param data The MQTTClient_handleAuthData. + * @return a negative value to indicate not-authorized, a value of 0 to indicate success, + * a positive value to indicate continue. */ typedef int MQTTClient_handleAuth(void* context, MQTTClient_handleAuthData* data); @@ -1045,19 +1049,19 @@ typedef struct 0, NULL, MQTTVERSION_DEFAULT, {NULL, 0, 0}, {0, NULL}, -1, 0, NULL, NULL, NULL, NULL} /** Initializer for connect options for MQTT 5.0 non-WebSocket connections */ -#define MQTTClient_connectOptions_initializer5 { {'M', 'Q', 'T', 'C'}, 8, 60, 0, 1, NULL, NULL, NULL, 30, 0, NULL,\ +#define MQTTClient_connectOptions_initializer5 { {'M', 'Q', 'T', 'C'}, 9, 60, 0, 1, NULL, NULL, NULL, 30, 0, NULL,\ 0, NULL, MQTTVERSION_5, {NULL, 0, 0}, {0, NULL}, -1, 1, NULL, NULL, NULL, NULL} /** Initializer for connect options for MQTT 3.1.1 WebSockets connections. * The keepalive interval is set to 45 seconds to avoid webserver 60 second inactivity timeouts. */ -#define MQTTClient_connectOptions_initializer_ws { {'M', 'Q', 'T', 'C'}, 8, 45, 1, 1, NULL, NULL, NULL, 30, 0, NULL,\ +#define MQTTClient_connectOptions_initializer_ws { {'M', 'Q', 'T', 'C'}, 9, 45, 1, 1, NULL, NULL, NULL, 30, 0, NULL,\ 0, NULL, MQTTVERSION_DEFAULT, {NULL, 0, 0}, {0, NULL}, -1, 0, NULL, NULL, NULL, NULL} /** Initializer for connect options for MQTT 5.0 WebSockets connections. * The keepalive interval is set to 45 seconds to avoid webserver 60 second inactivity timeouts. */ -#define MQTTClient_connectOptions_initializer5_ws { {'M', 'Q', 'T', 'C'}, 8, 45, 0, 1, NULL, NULL, NULL, 30, 0, NULL,\ +#define MQTTClient_connectOptions_initializer5_ws { {'M', 'Q', 'T', 'C'}, 9, 45, 0, 1, NULL, NULL, NULL, 30, 0, NULL,\ 0, NULL, MQTTVERSION_5, {NULL, 0, 0}, {0, NULL}, -1, 1, NULL, NULL, NULL, NULL} /** @@ -1453,15 +1457,6 @@ LIBMQTT_API int MQTTClient_receive(MQTTClient handle, char** topicName, int* top */ LIBMQTT_API void MQTTClient_freeMessage(MQTTClient_message** msg); -/** - * This function is used to allocate memory to be used or freed by the MQTT C client library, - * especially the data in the ::MQTTPersistence_afterRead and ::MQTTPersistence_beforeWrite - * callbacks. This is needed on Windows when the client library and application - * program have been compiled with different versions of the C compiler. - * @param size The size of the memory to be allocated. - */ -LIBMQTT_API void* MQTTClient_malloc(size_t size); - /** * This function frees memory allocated by the MQTT C client library, especially the * topic name. This is needed on Windows when the client libary and application