Skip to content

Commit

Permalink
Multistep auth, plus reauth, plus tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
ralight committed Apr 4, 2019
1 parent c1776a0 commit 2e7dcee
Show file tree
Hide file tree
Showing 22 changed files with 509 additions and 27 deletions.
2 changes: 1 addition & 1 deletion lib/mosquitto.h
Original file line number Diff line number Diff line change
Expand Up @@ -2829,7 +2829,7 @@ libmosq_EXPORT const mosquitto_property *mosquitto_property_read_binary(
const mosquitto_property *proplist,
int identifier,
void **value,
int *len,
uint16_t *len,
bool skip_first);

/*
Expand Down
4 changes: 2 additions & 2 deletions lib/mosquitto_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ enum mosquitto_client_state {
mosq_cs_duplicate = 17, /* client that has been taken over by another with the same id */
mosq_cs_disconnect_with_will = 18,
mosq_cs_disused = 19, /* client that has been added to the disused list to be freed */
mosq_cs_authentication = 20, /* Client has sent CONNECT but is still undergoing extended authentication */
mosq_cs_reauthentiction = 21, /* Client is undergoing reauthentication and shouldn't do anything else until complete */
mosq_cs_authenticating = 20, /* Client has sent CONNECT but is still undergoing extended authentication */
mosq_cs_reauthenticating = 21, /* Client is undergoing reauthentication and shouldn't do anything else until complete */
};

enum mosquitto__protocol {
Expand Down
2 changes: 1 addition & 1 deletion lib/property_mosq.c
Original file line number Diff line number Diff line change
Expand Up @@ -992,7 +992,7 @@ const mosquitto_property *mosquitto_property_read_varint(const mosquitto_propert
}


const mosquitto_property *mosquitto_property_read_binary(const mosquitto_property *proplist, int identifier, void **value, int *len, bool skip_first)
const mosquitto_property *mosquitto_property_read_binary(const mosquitto_property *proplist, int identifier, void **value, uint16_t *len, bool skip_first)
{
const mosquitto_property *p;
if(!proplist || (value && !len) || (!value && len)) return NULL;
Expand Down
12 changes: 9 additions & 3 deletions lib/send_disconnect.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,15 @@ int send__disconnect(struct mosquitto *mosq, uint8_t reason_code, const mosquitt

assert(mosq);
#ifdef WITH_BROKER
# ifdef WITH_BRIDGE
log__printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending DISCONNECT", mosq->id);
# endif
# ifdef WITH_BRIDGE
if(mosq->bridge){
log__printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending DISCONNECT", mosq->id);
}else
# else
{
log__printf(mosq, MOSQ_LOG_DEBUG, "Sending DISCONNECT to %s (rc%d)", mosq->id, reason_code);
}
# endif
#else
log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending DISCONNECT", mosq->id);
#endif
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ set (MOSQ_SRCS
../lib/read_handle.h
security.c security_default.c
../lib/send_mosq.c ../lib/send_mosq.h
send_auth.c
send_connack.c
../lib/send_connect.c
../lib/send_disconnect.c
Expand Down
4 changes: 4 additions & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ OBJS= mosquitto.o \
read_handle.o \
security.o \
security_default.o \
send_auth.o \
send_connack.o \
send_connect.o \
send_disconnect.o \
Expand Down Expand Up @@ -190,6 +191,9 @@ security.o : security.c mosquitto_broker_internal.h
security_default.o : security_default.c mosquitto_broker_internal.h
${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@

send_auth.o : send_auth.c mosquitto_broker_internal.h
${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@

send_connect.o : ../lib/send_connect.c ../lib/send_mosq.h
${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@

Expand Down
112 changes: 105 additions & 7 deletions src/handle_auth.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright (c) 2018 Roger Light <[email protected]>
Copyright (c) 2018-2019 Roger Light <[email protected]>
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
Expand All @@ -21,6 +21,7 @@ and the Eclipse Distribution License is available at

#include "mosquitto_broker_internal.h"
#include "mqtt_protocol.h"
#include "memory_mosq.h"
#include "packet_mosq.h"
#include "property_mosq.h"
#include "send_mosq.h"
Expand All @@ -31,23 +32,120 @@ int handle__auth(struct mosquitto_db *db, struct mosquitto *context)
int rc = 0;
uint8_t reason_code = 0;
mosquitto_property *properties = NULL;
char *auth_method = NULL;
void *auth_data = NULL;
uint16_t auth_data_len = 0;
void *auth_data_out = NULL;
uint16_t auth_data_out_len = 0;

if(!context) return MOSQ_ERR_INVAL;
log__printf(NULL, MOSQ_LOG_DEBUG, "Received AUTH from %s", context->id);

if(context->protocol != mosq_p_mqtt5){
if(context->protocol != mosq_p_mqtt5 || context->auth_method == NULL){
return MOSQ_ERR_PROTOCOL;
}

if(context->in_packet.remaining_length > 0){
if(packet__read_byte(&context->in_packet, &reason_code)) return 1;
if(reason_code != MQTT_RC_CONTINUE_AUTHENTICATION
&& reason_code != MQTT_RC_REAUTHENTICATE){

send__disconnect(context, MQTT_RC_PROTOCOL_ERROR, NULL);
return MOSQ_ERR_PROTOCOL;
}

if((reason_code == MQTT_RC_REAUTHENTICATE && context->state != mosq_cs_connected)
|| (reason_code == MQTT_RC_CONTINUE_AUTHENTICATION
&& context->state != mosq_cs_authenticating && context->state != mosq_cs_reauthenticating)){

send__disconnect(context, MQTT_RC_PROTOCOL_ERROR, NULL);
return MOSQ_ERR_PROTOCOL;
}

rc = property__read_all(CMD_AUTH, &context->in_packet, &properties);
if(rc) return rc;
if(rc){
send__disconnect(context, MQTT_RC_UNSPECIFIED, NULL);
return rc;
}


if(mosquitto_property_read_string(properties, MQTT_PROP_AUTHENTICATION_METHOD, &auth_method, false) == NULL){
mosquitto_property_free_all(&properties);
send__disconnect(context, MQTT_RC_UNSPECIFIED, NULL);
return MOSQ_ERR_PROTOCOL;
}

if(!auth_method || strcmp(auth_method, context->auth_method)){
/* No method, or non-matching method */
mosquitto__free(auth_method);
mosquitto_property_free_all(&properties);
send__disconnect(context, MQTT_RC_PROTOCOL_ERROR, NULL);
return MOSQ_ERR_PROTOCOL;
}
mosquitto__free(auth_method);

mosquitto_property_read_binary(properties, MQTT_PROP_AUTHENTICATION_DATA, &auth_data, &auth_data_len, false);

mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */
}

/* FIXME - Extended auth not currently supported */
send__disconnect(context, MQTT_RC_NOT_AUTHORIZED, NULL);
return 1;
log__printf(NULL, MOSQ_LOG_DEBUG, "Received AUTH from %s (rc%d, %s)", context->id, reason_code, context->auth_method);


if(reason_code == MQTT_RC_REAUTHENTICATE){
/* This is a re-authentication attempt */
context__set_state(context, mosq_cs_reauthenticating);
rc = mosquitto_security_auth_start(db, context, true, auth_data, auth_data_len, &auth_data_out, &auth_data_out_len);
}else{
if(context->state != mosq_cs_reauthenticating){
context__set_state(context, mosq_cs_authenticating);
}
rc = mosquitto_security_auth_continue(db, context, auth_data, auth_data_len, &auth_data_out, &auth_data_out_len);
}
mosquitto__free(auth_data);
if(rc == MOSQ_ERR_SUCCESS){
if(context->state == mosq_cs_authenticating){
return connect__on_authorised(db, context, auth_data_out, auth_data_out_len);
}else{
context__set_state(context, mosq_cs_connected);
rc = send__auth(db, context, MQTT_RC_SUCCESS, auth_data_out, auth_data_out_len);
free(auth_data_out);
return rc;
}
}else if(rc == MOSQ_ERR_AUTH_CONTINUE){
rc = send__auth(db, context, MQTT_RC_CONTINUE_AUTHENTICATION, auth_data_out, auth_data_out_len);
free(auth_data_out);
return rc;
}else{
free(auth_data_out);
if(context->state == mosq_cs_authenticating && context->will){
/* Free will without sending if this is our first authentication attempt */
mosquitto_property_free_all(&context->will->properties);
mosquitto__free(context->will->msg.payload);
mosquitto__free(context->will->msg.topic);
mosquitto__free(context->will);
context->will = NULL;
}
if(rc == MOSQ_ERR_AUTH){
send__connack(db, context, 0, MQTT_RC_NOT_AUTHORIZED, NULL);
if(context->state == mosq_cs_authenticating){
mosquitto__free(context->id);
context->id = NULL;
}
return MOSQ_ERR_PROTOCOL;
}else if(rc == MOSQ_ERR_NOT_SUPPORTED){
/* Client has requested extended authentication, but we don't support it. */
send__connack(db, context, 0, MQTT_RC_BAD_AUTHENTICATION_METHOD, NULL);
if(context->state == mosq_cs_authenticating){
mosquitto__free(context->id);
context->id = NULL;
}
return MOSQ_ERR_PROTOCOL;
}else{
if(context->state == mosq_cs_authenticating){
mosquitto__free(context->id);
context->id = NULL;
}
return rc;
}
}
}
8 changes: 6 additions & 2 deletions src/handle_connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context)
int i;
mosquitto_property *properties = NULL;
void *auth_data = NULL;
int auth_data_len = 0;
uint16_t auth_data_len = 0;
void *auth_data_out = NULL;
uint16_t auth_data_out_len = 0;
#ifdef WITH_TLS
Expand Down Expand Up @@ -817,8 +817,12 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context)
if(rc == MOSQ_ERR_SUCCESS){
return connect__on_authorised(db, context, auth_data_out, auth_data_out_len);
}else if(rc == MOSQ_ERR_AUTH_CONTINUE){
return 1; // FIXME
context__set_state(context, mosq_cs_authenticating);
rc = send__auth(db, context, MQTT_RC_CONTINUE_AUTHENTICATION, auth_data_out, auth_data_out_len);
free(auth_data_out);
return rc;
}else{
free(auth_data_out);
if(context->will){
mosquitto_property_free_all(&context->will->properties);
mosquitto__free(context->will->msg.payload);
Expand Down
9 changes: 6 additions & 3 deletions src/mosquitto_broker_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ typedef int (*FUNC_auth_plugin_acl_check_v4)(void *, int, struct mosquitto *, st
typedef int (*FUNC_auth_plugin_unpwd_check_v4)(void *, struct mosquitto *, const char *, const char *);
typedef int (*FUNC_auth_plugin_psk_key_get_v4)(void *, struct mosquitto *, const char *, const char *, char *, int);
typedef int (*FUNC_auth_plugin_auth_start_v4)(void *, struct mosquitto *, const char *, bool, const void *, uint16_t, void **, uint16_t *);
typedef int (*FUNC_auth_plugin_auth_continue_v4)(void *, struct mosquitto *, const char *, const void *, int);
typedef int (*FUNC_auth_plugin_auth_continue_v4)(void *, struct mosquitto *, const char *, const void *, uint16_t, void **, uint16_t *);

typedef int (*FUNC_auth_plugin_init_v3)(void **, struct mosquitto_opt *, int);
typedef int (*FUNC_auth_plugin_cleanup_v3)(void *, struct mosquitto_opt *, int);
Expand Down Expand Up @@ -564,6 +564,7 @@ int restore_privileges(void);
int send__connack(struct mosquitto_db *db, struct mosquitto *context, int ack, int reason_code, const mosquitto_property *properties);
int send__suback(struct mosquitto *context, uint16_t mid, uint32_t payloadlen, const void *payload);
int send__unsuback(struct mosquitto *context, uint16_t mid, int reason_code_count, uint8_t *reason_codes, const mosquitto_property *properties);
int send__auth(struct mosquitto_db *db, struct mosquitto *context, int reason_code, const void *auth_data, uint16_t auth_data_len);

/* ============================================================
* Network functions
Expand Down Expand Up @@ -640,6 +641,8 @@ void context__send_will(struct mosquitto_db *db, struct mosquitto *context);
void context__remove_from_by_id(struct mosquitto_db *db, struct mosquitto *context);
void context__set_state(struct mosquitto *context, enum mosquitto_client_state state);

int connect__on_authorised(struct mosquitto_db *db, struct mosquitto *context, void *auth_data_out, uint16_t auth_data_out_len);

/* ============================================================
* Logging functions
* ============================================================ */
Expand Down Expand Up @@ -688,8 +691,8 @@ int mosquitto_acl_check_default(struct mosquitto_db *db, struct mosquitto *conte
int mosquitto_unpwd_check_default(struct mosquitto_db *db, struct mosquitto *context, const char *username, const char *password);
int mosquitto_psk_key_get_default(struct mosquitto_db *db, struct mosquitto *context, const char *hint, const char *identity, char *key, int max_key_len);

int mosquitto_security_auth_start(struct mosquitto_db *db, struct mosquitto *context, bool reauth, const void *data_in, int data_in_len, void **data_out, uint16_t *data_out_len);
int mosquitto_security_auth_continue(struct mosquitto_db *db, struct mosquitto *context, const void *auth_data, int auth_data_len);
int mosquitto_security_auth_start(struct mosquitto_db *db, struct mosquitto *context, bool reauth, const void *data_in, uint16_t data_in_len, void **data_out, uint16_t *data_out_len);
int mosquitto_security_auth_continue(struct mosquitto_db *db, struct mosquitto *context, const void *data_in, uint16_t data_len, void **data_out, uint16_t *data_out_len);

/* ============================================================
* Session expiry
Expand Down
2 changes: 2 additions & 0 deletions src/mosquitto_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,4 +293,6 @@ int mosquitto_auth_psk_key_get(void *user_data, struct mosquitto *client, const
* Return any other relevant positive integer MOSQ_ERR_* to produce an error.
*/
int mosquitto_auth_start(void *user_data, struct mosquitto *client, const char *method, bool reauth, const void *data_in, uint16_t data_in_len, void **data_out, uint16_t *data_out_len);

int mosquitto_auth_continue(void *user_data, struct mosquitto *client, const char *method, const void *data_in, uint16_t data_in_len, void **data_out, uint16_t *data_out_len);
#endif
49 changes: 48 additions & 1 deletion src/security.c
Original file line number Diff line number Diff line change
Expand Up @@ -796,7 +796,7 @@ int mosquitto_psk_key_get(struct mosquitto_db *db, struct mosquitto *context, co
}


int mosquitto_security_auth_start(struct mosquitto_db *db, struct mosquitto *context, bool reauth, const void *data_in, int data_in_len, void **data_out, uint16_t *data_out_len)
int mosquitto_security_auth_start(struct mosquitto_db *db, struct mosquitto *context, bool reauth, const void *data_in, uint16_t data_in_len, void **data_out, uint16_t *data_out_len)
{
int rc = MOSQ_ERR_PLUGIN_DEFER;
int i;
Expand Down Expand Up @@ -842,3 +842,50 @@ int mosquitto_security_auth_start(struct mosquitto_db *db, struct mosquitto *con
return rc;
}
}


int mosquitto_security_auth_continue(struct mosquitto_db *db, struct mosquitto *context, const void *data_in, uint16_t data_in_len, void **data_out, uint16_t *data_out_len)
{
int rc = MOSQ_ERR_PLUGIN_DEFER;
int i;
struct mosquitto__security_options *opts;

if(!context || !context->listener || !context->auth_method) return MOSQ_ERR_INVAL;
if(!data_out || !data_out_len) return MOSQ_ERR_INVAL;

if(db->config->per_listener_settings){
opts = &context->listener->security_options;
}else{
opts = &db->config->security_options;
}

for(i=0; i<opts->auth_plugin_config_count; i++){
if(opts->auth_plugin_configs[i].plugin.auth_start_v4){
*data_out = NULL;
*data_out_len = 0;

rc = opts->auth_plugin_configs[i].plugin.auth_continue_v4(
opts->auth_plugin_configs[i].plugin.user_data,
context,
context->auth_method,
data_in, data_in_len,
data_out, data_out_len);

if(rc == MOSQ_ERR_SUCCESS){
return MOSQ_ERR_SUCCESS;
}else if(rc == MOSQ_ERR_AUTH_CONTINUE){
return MOSQ_ERR_AUTH_CONTINUE;
}else if(rc == MOSQ_ERR_NOT_SUPPORTED){
rc = MOSQ_ERR_PLUGIN_DEFER;
}else{
return rc;
}
}
}

if(rc == MOSQ_ERR_PLUGIN_DEFER){
return MOSQ_ERR_NOT_SUPPORTED;
}else{
return rc;
}
}
Loading

0 comments on commit 2e7dcee

Please sign in to comment.