diff --git a/src/handle_connect.c b/src/handle_connect.c index d2e1cebf..d971725b 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -100,7 +100,7 @@ void connection_check_acl(struct mosquitto_db *db, struct mosquitto *context, st } -int connect__on_authorised(struct mosquitto_db *db, struct mosquitto *context) +int connect__on_authorised(struct mosquitto_db *db, struct mosquitto *context, void *auth_data_out, uint16_t auth_data_out_len) { struct mosquitto *found_context; struct mosquitto__subleaf *leaf; @@ -164,7 +164,10 @@ int connect__on_authorised(struct mosquitto_db *db, struct mosquitto *context) } rc = acl__find_acls(db, context); - if(rc) return rc; + if(rc){ + free(auth_data_out); + return rc; + } if(db->config->connection_messages == true){ if(context->is_bridge){ @@ -243,14 +246,23 @@ int connect__on_authorised(struct mosquitto_db *db, struct mosquitto *context) rc = MOSQ_ERR_NOMEM; goto error; } + + if(auth_data_out && auth_data_out_len > 0){ + if(mosquitto_property_add_binary(&connack_props, MQTT_PROP_AUTHENTICATION_DATA, auth_data_out, auth_data_out_len)){ + rc = MOSQ_ERR_NOMEM; + goto error; + } + } } } + free(auth_data_out); context__set_state(context, mosq_cs_connected); rc = send__connack(db, context, connect_ack, CONNACK_ACCEPTED, connack_props); mosquitto_property_free_all(&connack_props); return rc; error: + free(auth_data_out); mosquitto_property_free_all(&connack_props); return rc; } @@ -353,6 +365,8 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) mosquitto_property *properties = NULL; void *auth_data = NULL; int auth_data_len = 0; + void *auth_data_out = NULL; + uint16_t auth_data_out_len = 0; #ifdef WITH_TLS X509 *client_cert = NULL; X509_NAME *name; @@ -797,12 +811,11 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) context->id = client_id; context->will = will_struct; - if(context->auth_method){ - rc = mosquitto_security_auth_start(db, context, auth_data, auth_data_len); + rc = mosquitto_security_auth_start(db, context, auth_data, auth_data_len, &auth_data_out, &auth_data_out_len); mosquitto__free(auth_data); if(rc == MOSQ_ERR_SUCCESS){ - return connect__on_authorised(db, context); + return connect__on_authorised(db, context, auth_data_out, auth_data_out_len); }else if(rc == MOSQ_ERR_AUTH_CONTINUE){ return 1; // FIXME }else{ @@ -831,7 +844,7 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context) } } }else{ - return connect__on_authorised(db, context); + return connect__on_authorised(db, context, NULL, 0); } diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 22c45071..0a3edf30 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -138,7 +138,7 @@ typedef int (*FUNC_auth_plugin_security_cleanup_v4)(void *, struct mosquitto_opt typedef int (*FUNC_auth_plugin_acl_check_v4)(void *, int, struct mosquitto *, struct mosquitto_acl_msg *); 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 *, const void *, int); +typedef int (*FUNC_auth_plugin_auth_start_v4)(void *, struct mosquitto *, const char *, 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_init_v3)(void **, struct mosquitto_opt *, int); @@ -688,7 +688,7 @@ 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, const void *auth_data, int auth_data_len); +int mosquitto_security_auth_start(struct mosquitto_db *db, struct mosquitto *context, 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); /* ============================================================ diff --git a/src/mosquitto_plugin.h b/src/mosquitto_plugin.h index 2b338fd7..e2fb4bfc 100644 --- a/src/mosquitto_plugin.h +++ b/src/mosquitto_plugin.h @@ -272,6 +272,16 @@ int mosquitto_auth_psk_key_get(void *user_data, struct mosquitto *client, const * * This function is OPTIONAL. Only include this function in your plugin if you * are making extended authentication checks. + * + * Parameters: + * user_data : the pointer provided in . + * method : the authentication method + * data_in : pointer to authentication data, or NULL + * data_in_len : length of data_in, in bytes + * data_out : if your plugin wishes to send authentication data back to the + * client, allocate some memory using malloc or friends and set + * data_out. The broker will free the memory after use. + * data_out_len : Set the length of data_out in bytes. */ -int mosquitto_auth_start(void *user_data, struct mosquitto *client, const char *method, const void *data, int data_len); +int mosquitto_auth_start(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 diff --git a/src/security.c b/src/security.c index 07905b02..58e17319 100644 --- a/src/security.c +++ b/src/security.c @@ -796,13 +796,14 @@ 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, const void *auth_data, int auth_data_len) +int mosquitto_security_auth_start(struct mosquitto_db *db, struct mosquitto *context, const void *data_in, int 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; @@ -812,12 +813,15 @@ int mosquitto_security_auth_start(struct mosquitto_db *db, struct mosquitto *con for(i=0; iauth_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_start_v4( opts->auth_plugin_configs[i].plugin.user_data, context, context->auth_method, - auth_data, - auth_data_len); + data_in, data_in_len, + data_out, data_out_len); if(rc == MOSQ_ERR_SUCCESS){ return MOSQ_ERR_SUCCESS; diff --git a/test/broker/09-extended-auth-change-username.py b/test/broker/09-extended-auth-change-username.py index c040061b..05b4447a 100755 --- a/test/broker/09-extended-auth-change-username.py +++ b/test/broker/09-extended-auth-change-username.py @@ -82,6 +82,6 @@ def do_test(per_listener): exit(rc) -#do_test("true") +do_test("true") do_test("false") exit(0) diff --git a/test/broker/09-extended-auth-single.py b/test/broker/09-extended-auth-single.py index dc8eff19..2b7ba340 100755 --- a/test/broker/09-extended-auth-single.py +++ b/test/broker/09-extended-auth-single.py @@ -1,5 +1,13 @@ #!/usr/bin/env python +# Multi tests for extended auth with a single step. +# * Error in plugin +# * No matching authentication method +# * Matching authentication method, but auth rejected +# * Matching authentication method, auth succeeds +# * Matching authentication method, auth succeeds, new auth data sent back to client + + from mosq_test_helper import * def write_config(filename, port): @@ -35,6 +43,14 @@ connect4_packet = mosq_test.gen_connect("client-params-test5", keepalive=42, pro props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_AUTHENTICATION_METHOD, "single") connack4_packet = mosq_test.gen_connack(rc=0, proto_ver=5, properties=props) +# Single step, matching method, success, auth data back to client +props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_AUTHENTICATION_METHOD, "mirror") +props += mqtt5_props.gen_string_prop(mqtt5_props.PROP_AUTHENTICATION_DATA, "somedata") +connect5_packet = mosq_test.gen_connect("client-params-test6", keepalive=42, proto_ver=5, properties=props) +props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_AUTHENTICATION_METHOD, "mirror") +props += mqtt5_props.gen_string_prop(mqtt5_props.PROP_AUTHENTICATION_DATA, "atademos") +connack5_packet = mosq_test.gen_connack(rc=0, proto_ver=5, properties=props) + broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port) @@ -51,6 +67,9 @@ try: sock = mosq_test.do_client_connect(connect4_packet, connack4_packet, timeout=20, port=port) sock.close() + sock = mosq_test.do_client_connect(connect5_packet, connack5_packet, timeout=20, port=port) + sock.close() + rc = 0 finally: os.remove(conf_file) diff --git a/test/broker/09-extended-auth-single2.py b/test/broker/09-extended-auth-single2.py new file mode 100755 index 00000000..d86f9177 --- /dev/null +++ b/test/broker/09-extended-auth-single2.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python + +# Multi tests for extended auth with a single step - multiple plugins at once. +# * Error in plugin +# * No matching authentication method +# * Matching authentication method, but auth rejected +# * Matching authentication method, auth succeeds +# * Matching authentication method, auth succeeds, new auth data sent back to client + + +from mosq_test_helper import * + +def write_config(filename, port): + with open(filename, 'w') as f: + f.write("port %d\n" % (port)) + f.write("auth_plugin c/auth_plugin_extended_single.so\n") + f.write("auth_plugin c/auth_plugin_extended_single2.so\n") + +port = mosq_test.get_port() +conf_file = os.path.basename(__file__).replace('.py', '.conf') + + +def do_test(suffix): + write_config(conf_file, port) + rc = 1 + # Single, error in plugin + props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_AUTHENTICATION_METHOD, "error%s" % (suffix)) + connect1_packet = mosq_test.gen_connect("client-params-test1", keepalive=42, proto_ver=5, properties=props) + + # Single, no matching authentication method + props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_AUTHENTICATION_METHOD, "non-matching%s" % (suffix)) + connect2_packet = mosq_test.gen_connect("client-params-test2", keepalive=42, proto_ver=5, properties=props) + connack2_packet = mosq_test.gen_connack(rc=mqtt5_rc.MQTT_RC_BAD_AUTHENTICATION_METHOD, proto_ver=5, properties=None) + + # Single step, matching method, failure + props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_AUTHENTICATION_METHOD, "single%s" % (suffix)) + props += mqtt5_props.gen_string_prop(mqtt5_props.PROP_AUTHENTICATION_DATA, "baddata") + connect3_packet = mosq_test.gen_connect("client-params-test3", keepalive=42, proto_ver=5, properties=props) + connack3_packet = mosq_test.gen_connack(rc=mqtt5_rc.MQTT_RC_NOT_AUTHORIZED, proto_ver=5, properties=None) + + # Single step, matching method, success + props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_AUTHENTICATION_METHOD, "single%s" % (suffix)) + props += mqtt5_props.gen_string_prop(mqtt5_props.PROP_AUTHENTICATION_DATA, "data") + connect4_packet = mosq_test.gen_connect("client-params-test5", keepalive=42, proto_ver=5, properties=props) + props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_AUTHENTICATION_METHOD, "single%s" % (suffix)) + connack4_packet = mosq_test.gen_connack(rc=0, proto_ver=5, properties=props) + + # Single step, matching method, success, auth data back to client + props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_AUTHENTICATION_METHOD, "mirror%s" % (suffix)) + props += mqtt5_props.gen_string_prop(mqtt5_props.PROP_AUTHENTICATION_DATA, "somedata") + connect5_packet = mosq_test.gen_connect("client-params-test6", keepalive=42, proto_ver=5, properties=props) + props = mqtt5_props.gen_string_prop(mqtt5_props.PROP_AUTHENTICATION_METHOD, "mirror%s" % (suffix)) + props += mqtt5_props.gen_string_prop(mqtt5_props.PROP_AUTHENTICATION_DATA, "atademos") + connack5_packet = mosq_test.gen_connack(rc=0, proto_ver=5, properties=props) + + + broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port) + + try: + sock = mosq_test.do_client_connect(connect1_packet, b"", timeout=20, port=port) + sock.close() + + sock = mosq_test.do_client_connect(connect2_packet, connack2_packet, timeout=20, port=port) + sock.close() + + sock = mosq_test.do_client_connect(connect3_packet, connack3_packet, timeout=20, port=port) + sock.close() + + sock = mosq_test.do_client_connect(connect4_packet, connack4_packet, timeout=20, port=port) + sock.close() + + sock = mosq_test.do_client_connect(connect5_packet, connack5_packet, timeout=20, port=port) + sock.close() + + rc = 0 + finally: + os.remove(conf_file) + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde.decode('utf-8')) + exit(rc) + +do_test("") +do_test("2") +exit(0) + diff --git a/test/broker/c/Makefile b/test/broker/c/Makefile index 8305354f..7058769c 100644 --- a/test/broker/c/Makefile +++ b/test/broker/c/Makefile @@ -10,7 +10,8 @@ PLUGIN_SRC = \ auth_plugin_v2.c \ auth_plugin_context_params.c \ auth_plugin_msg_params.c \ - auth_plugin_extended_single.c + auth_plugin_extended_single.c \ + auth_plugin_extended_single2.c PLUGINS = ${PLUGIN_SRC:.c=.so} diff --git a/test/broker/c/auth_plugin.c b/test/broker/c/auth_plugin.c index ddb098b2..07796084 100644 --- a/test/broker/c/auth_plugin.c +++ b/test/broker/c/auth_plugin.c @@ -29,7 +29,7 @@ int mosquitto_auth_security_cleanup(void *user_data, struct mosquitto_opt *auth_ return MOSQ_ERR_SUCCESS; } -int mosquitto_auth_acl_check(void *user_data, int access, const struct mosquitto *client, const struct mosquitto_acl_msg *msg) +int mosquitto_auth_acl_check(void *user_data, int access, struct mosquitto *client, const struct mosquitto_acl_msg *msg) { const char *username = mosquitto_client_username(client); @@ -42,7 +42,7 @@ int mosquitto_auth_acl_check(void *user_data, int access, const struct mosquitto } } -int mosquitto_auth_unpwd_check(void *user_data, const struct mosquitto *client, const char *username, const char *password) +int mosquitto_auth_unpwd_check(void *user_data, struct mosquitto *client, const char *username, const char *password) { if(!strcmp(username, "test-username") && password && !strcmp(password, "cnwTICONIURW")){ return MOSQ_ERR_SUCCESS; @@ -55,7 +55,7 @@ int mosquitto_auth_unpwd_check(void *user_data, const struct mosquitto *client, } } -int mosquitto_auth_psk_key_get(void *user_data, const struct mosquitto *client, const char *hint, const char *identity, char *key, int max_key_len) +int mosquitto_auth_psk_key_get(void *user_data, struct mosquitto *client, const char *hint, const char *identity, char *key, int max_key_len) { return MOSQ_ERR_AUTH; } diff --git a/test/broker/c/auth_plugin_acl.c b/test/broker/c/auth_plugin_acl.c index 4a89eedb..90d10e01 100644 --- a/test/broker/c/auth_plugin_acl.c +++ b/test/broker/c/auth_plugin_acl.c @@ -29,7 +29,7 @@ int mosquitto_auth_security_cleanup(void *user_data, struct mosquitto_opt *auth_ return MOSQ_ERR_SUCCESS; } -int mosquitto_auth_acl_check(void *user_data, int access, const struct mosquitto *client, const struct mosquitto_acl_msg *msg) +int mosquitto_auth_acl_check(void *user_data, int access, struct mosquitto *client, const struct mosquitto_acl_msg *msg) { const char *username = mosquitto_client_username(client); @@ -42,12 +42,12 @@ int mosquitto_auth_acl_check(void *user_data, int access, const struct mosquitto } } -int mosquitto_auth_unpwd_check(void *user_data, const struct mosquitto *client, const char *username, const char *password) +int mosquitto_auth_unpwd_check(void *user_data, struct mosquitto *client, const char *username, const char *password) { return MOSQ_ERR_PLUGIN_DEFER; } -int mosquitto_auth_psk_key_get(void *user_data, const struct mosquitto *client, const char *hint, const char *identity, char *key, int max_key_len) +int mosquitto_auth_psk_key_get(void *user_data, struct mosquitto *client, const char *hint, const char *identity, char *key, int max_key_len) { return MOSQ_ERR_AUTH; } diff --git a/test/broker/c/auth_plugin_acl_sub_denied.c b/test/broker/c/auth_plugin_acl_sub_denied.c index 4c5a26fa..d6147df9 100644 --- a/test/broker/c/auth_plugin_acl_sub_denied.c +++ b/test/broker/c/auth_plugin_acl_sub_denied.c @@ -29,7 +29,7 @@ int mosquitto_auth_security_cleanup(void *user_data, struct mosquitto_opt *auth_ return MOSQ_ERR_SUCCESS; } -int mosquitto_auth_acl_check(void *user_data, int access, const struct mosquitto *client, const struct mosquitto_acl_msg *msg) +int mosquitto_auth_acl_check(void *user_data, int access, struct mosquitto *client, const struct mosquitto_acl_msg *msg) { if(access == MOSQ_ACL_SUBSCRIBE){ return MOSQ_ERR_ACL_DENIED; @@ -38,12 +38,12 @@ int mosquitto_auth_acl_check(void *user_data, int access, const struct mosquitto } } -int mosquitto_auth_unpwd_check(void *user_data, const struct mosquitto *client, const char *username, const char *password) +int mosquitto_auth_unpwd_check(void *user_data, struct mosquitto *client, const char *username, const char *password) { return MOSQ_ERR_SUCCESS; } -int mosquitto_auth_psk_key_get(void *user_data, const struct mosquitto *client, const char *hint, const char *identity, char *key, int max_key_len) +int mosquitto_auth_psk_key_get(void *user_data, struct mosquitto *client, const char *hint, const char *identity, char *key, int max_key_len) { return MOSQ_ERR_AUTH; } diff --git a/test/broker/c/auth_plugin_context_params.c b/test/broker/c/auth_plugin_context_params.c index 73c64f98..5fbc9c13 100644 --- a/test/broker/c/auth_plugin_context_params.c +++ b/test/broker/c/auth_plugin_context_params.c @@ -30,12 +30,12 @@ int mosquitto_auth_security_cleanup(void *user_data, struct mosquitto_opt *auth_ return MOSQ_ERR_SUCCESS; } -int mosquitto_auth_acl_check(void *user_data, int access, const struct mosquitto *client, const struct mosquitto_acl_msg *msg) +int mosquitto_auth_acl_check(void *user_data, int access, struct mosquitto *client, const struct mosquitto_acl_msg *msg) { return MOSQ_ERR_PLUGIN_DEFER; } -int mosquitto_auth_unpwd_check(void *user_data, const struct mosquitto *client, const char *username, const char *password) +int mosquitto_auth_unpwd_check(void *user_data, struct mosquitto *client, const char *username, const char *password) { const char *tmp; @@ -84,7 +84,7 @@ int mosquitto_auth_unpwd_check(void *user_data, const struct mosquitto *client, return MOSQ_ERR_SUCCESS; } -int mosquitto_auth_psk_key_get(void *user_data, const struct mosquitto *client, const char *hint, const char *identity, char *key, int max_key_len) +int mosquitto_auth_psk_key_get(void *user_data, struct mosquitto *client, const char *hint, const char *identity, char *key, int max_key_len) { return MOSQ_ERR_AUTH; } diff --git a/test/broker/c/auth_plugin_extended_single.c b/test/broker/c/auth_plugin_extended_single.c index 3abb2bf9..87c25db2 100644 --- a/test/broker/c/auth_plugin_extended_single.c +++ b/test/broker/c/auth_plugin_extended_single.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -35,8 +36,10 @@ int mosquitto_auth_acl_check(void *user_data, int access, struct mosquitto *clie } -int mosquitto_auth_start(void *user_data, struct mosquitto *client, const char *method, const void *data, int data_len) +int mosquitto_auth_start(void *user_data, struct mosquitto *client, const char *method, const void *data, uint16_t data_len, void **data_out, uint16_t *data_out_len) { + int i; + if(!strcmp(method, "error")){ return MOSQ_ERR_INVAL; }else if(!strcmp(method, "non-matching")){ @@ -50,6 +53,21 @@ int mosquitto_auth_start(void *user_data, struct mosquitto *client, const char * } }else if(!strcmp(method, "change")){ return mosquitto_set_username(client, "new_username"); + }else if(!strcmp(method, "mirror")){ + if(data_len > 0){ + *data_out = malloc(data_len); + if(!(*data_out)){ + return MOSQ_ERR_NOMEM; + } + for(i=0; i +#include +#include +#include +#include +#include + +int mosquitto_auth_plugin_version(void) +{ + return MOSQ_AUTH_PLUGIN_VERSION; +} + +int mosquitto_auth_plugin_init(void **user_data, struct mosquitto_opt *auth_opts, int auth_opt_count) +{ + return MOSQ_ERR_SUCCESS; +} + +int mosquitto_auth_plugin_cleanup(void *user_data, struct mosquitto_opt *auth_opts, int auth_opt_count) +{ + return MOSQ_ERR_SUCCESS; +} + +int mosquitto_auth_security_init(void *user_data, struct mosquitto_opt *auth_opts, int auth_opt_count, bool reload) +{ + return MOSQ_ERR_SUCCESS; +} + +int mosquitto_auth_security_cleanup(void *user_data, struct mosquitto_opt *auth_opts, int auth_opt_count, bool reload) +{ + return MOSQ_ERR_SUCCESS; +} + +int mosquitto_auth_acl_check(void *user_data, int access, struct mosquitto *client, const struct mosquitto_acl_msg *msg) +{ + return MOSQ_ERR_PLUGIN_DEFER; +} + + +int mosquitto_auth_start(void *user_data, struct mosquitto *client, const char *method, const void *data, uint16_t data_len, void **data_out, uint16_t *data_out_len) +{ + int i; + + if(!strcmp(method, "error2")){ + return MOSQ_ERR_INVAL; + }else if(!strcmp(method, "non-matching2")){ + return MOSQ_ERR_NOT_SUPPORTED; + }else if(!strcmp(method, "single2")){ + data_len = data_len>strlen("data")?strlen("data"):data_len; + if(!memcmp(data, "data", data_len)){ + return MOSQ_ERR_SUCCESS; + }else{ + return MOSQ_ERR_AUTH; + } + }else if(!strcmp(method, "change2")){ + return mosquitto_set_username(client, "new_username"); + }else if(!strcmp(method, "mirror2")){ + if(data_len > 0){ + *data_out = malloc(data_len); + if(!(*data_out)){ + return MOSQ_ERR_NOMEM; + } + for(i=0; i