diff --git a/include/errmsg.h b/include/errmsg.h index 7ca3238a..555cde19 100644 --- a/include/errmsg.h +++ b/include/errmsg.h @@ -101,7 +101,9 @@ extern const char *mariadb_client_errors[]; /* Error messages */ #define CR_BULK_WITHOUT_PARAMETERS 5006 #define CR_INVALID_STMT 5007 #define CR_VERSION_MISMATCH 5008 +#define CR_INVALID_PARAMETER 5009 +#define CR_PLUGIN_NOT_ALLOWED 5010 /* Always last, if you add new error codes please update the value for CR_MARIADB_LAST_ERROR */ -#define CR_MARIADB_LAST_ERROR CR_VERSION_MISMATCH +#define CR_MARIADB_LAST_ERROR CR_PLUGIN_NOT_ALLOWED #endif diff --git a/include/ma_common.h b/include/ma_common.h index 5bfdb7ad..efb709bc 100644 --- a/include/ma_common.h +++ b/include/ma_common.h @@ -80,6 +80,7 @@ struct st_mysql_options_extension { size_t proxy_header_len; int (*io_wait)(my_socket handle, my_bool is_read, int timeout); my_bool skip_read_response; + char *restricted_auth; }; typedef struct st_connection_handler diff --git a/include/mysql.h b/include/mysql.h index b66cf170..a36d86e1 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -247,7 +247,8 @@ extern const char *SQLSTATE_UNKNOWN; MARIADB_OPT_INTERACTIVE, MARIADB_OPT_PROXY_HEADER, MARIADB_OPT_IO_WAIT, - MARIADB_OPT_SKIP_READ_RESPONSE + MARIADB_OPT_SKIP_READ_RESPONSE, + MARIADB_OPT_RESTRICTED_AUTH }; enum mariadb_value { diff --git a/libmariadb/ma_errmsg.c b/libmariadb/ma_errmsg.c index ae247890..46769935 100644 --- a/libmariadb/ma_errmsg.c +++ b/libmariadb/ma_errmsg.c @@ -103,6 +103,8 @@ const char *mariadb_client_errors[] = /* 5006 */ "Bulk operation without parameters is not supported", /* 5007 */ "Invalid statement handle", /* 5008 */ "Unsupported version %d. Supported versions are in the range %d - %d", + /* 5009 */ "Invalid or missing parameter '%s'.", + /* 5010 */ "Authentication plugin '%s' couldn't be found in restricted_auth plugin list.", "" }; diff --git a/libmariadb/mariadb_lib.c b/libmariadb/mariadb_lib.c index 0ffe8cdb..2717906a 100644 --- a/libmariadb/mariadb_lib.c +++ b/libmariadb/mariadb_lib.c @@ -666,6 +666,7 @@ struct st_default_options mariadb_defaults[] = {MYSQL_SERVER_PUBLIC_KEY, MARIADB_OPTION_STR, "server-public-key"}, {MYSQL_OPT_BIND, MARIADB_OPTION_STR, "bind-address"}, {MYSQL_OPT_SSL_ENFORCE, MARIADB_OPTION_BOOL, "ssl-enforce"}, + {MARIADB_OPT_RESTRICTED_AUTH, MARIADB_OPTION_STR, "restricted-auth"}, {0, 0, NULL} }; @@ -1999,6 +2000,7 @@ static void mysql_close_options(MYSQL *mysql) ma_hashtbl_free(&mysql->options.extension->connect_attrs); if (ma_hashtbl_inited(&mysql->options.extension->userdata)) ma_hashtbl_free(&mysql->options.extension->userdata); + free(mysql->options.extension->restricted_auth); } free(mysql->options.extension); @@ -3367,6 +3369,9 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) case MARIADB_OPT_SKIP_READ_RESPONSE: OPT_SET_EXTENDED_VALUE_INT(&mysql->options, skip_read_response, *(my_bool *)arg1); break; + case MARIADB_OPT_RESTRICTED_AUTH: + OPT_SET_EXTENDED_VALUE_STR(&mysql->options, restricted_auth, (char *)arg1); + break; default: va_end(ap); SET_CLIENT_ERROR(mysql, CR_NOT_IMPLEMENTED, SQLSTATE_UNKNOWN, 0); diff --git a/plugins/auth/my_auth.c b/plugins/auth/my_auth.c index 2fd1ba12..8258179e 100644 --- a/plugins/auth/my_auth.c +++ b/plugins/auth/my_auth.c @@ -571,6 +571,7 @@ int run_plugin_auth(MYSQL *mysql, char *data, uint data_len, ulong pkt_length; int res; + /* determine the default/initial plugin to use */ if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH) { @@ -613,6 +614,17 @@ int run_plugin_auth(MYSQL *mysql, char *data, uint data_len, retry: mpvio.plugin= auth_plugin; + if (auth_plugin_name && + mysql->options.extension && + mysql->options.extension->restricted_auth) + { + if (!strstr(mysql->options.extension->restricted_auth, auth_plugin_name)) + { + my_set_error(mysql, CR_PLUGIN_NOT_ALLOWED, SQLSTATE_UNKNOWN, 0, data_plugin); + return 1; + } + } + mysql->net.read_pos[0]= 0; res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql); diff --git a/unittest/libmariadb/connection.c b/unittest/libmariadb/connection.c index 5cbea6ec..6b854310 100644 --- a/unittest/libmariadb/connection.c +++ b/unittest/libmariadb/connection.c @@ -1915,7 +1915,72 @@ static int test_conc490(MYSQL *my __attribute__((unused))) return OK; } +static int test_conc544(MYSQL *mysql) +{ + int rc; + MYSQL *my= mysql_init(NULL); + char query[1024]; + + if (!mysql_client_find_plugin(mysql, "client_ed25519", MYSQL_CLIENT_AUTHENTICATION_PLUGIN)) + { + diag("client_ed25519 plugin not available"); + return SKIP; + } + + rc= mysql_query(mysql, "INSTALL SONAME 'auth_ed25519'"); + if (rc) + { + diag("feature not supported, ed25519 plugin not available"); + return SKIP; + } + + rc= mysql_optionsv(my, MARIADB_OPT_RESTRICTED_AUTH, "client_ed25519"); + check_mysql_rc(rc, mysql); + + if (my_test_connect(my, hostname, username, + password, schema, port, socketname, 0)) + { + diag("error expected (restricted auth)"); + return FAIL; + } + mysql_close(my); + + if (mysql_get_server_version(mysql) < 100400) { + sprintf(query, "CREATE OR REPLACE USER 'ede'@'%s' IDENTIFIED VIA ed25519 USING '6aW9C7ENlasUfymtfMvMZZtnkCVlcb1ssxOLJ0kj/AA'", this_host); + } else { + sprintf(query, "CREATE OR REPLACE USER 'ede'@'%s' IDENTIFIED VIA ed25519 USING PASSWORD('MySup8%%rPassw@ord')", this_host); + } + rc= mysql_query(mysql, query); + check_mysql_rc(rc, mysql); + + sprintf(query, "GRANT ALL ON %s.* TO 'ede'@'%s'", schema, this_host); + rc= mysql_query(mysql, query); + check_mysql_rc(rc, mysql); + + my= mysql_init(NULL); + if (plugindir) + mysql_optionsv(my, MYSQL_PLUGIN_DIR, plugindir); + mysql_optionsv(my, MARIADB_OPT_RESTRICTED_AUTH, "client_ed25519, mysql_native_password"); + if (!my_test_connect(my, hostname, "ede", "MySup8%rPassw@ord", schema, port, socketname, 0)) + { + diag("Error: %s", mysql_error(my)); + return FAIL; + } + mysql_close(my); + + sprintf(query, "DROP USER 'ede'@'%s'", this_host); + rc= mysql_query(mysql, query); + check_mysql_rc(rc, mysql); + + sprintf(query, "UNINSTALL SONAME 'auth_ed25519'"); + rc= mysql_query(mysql, query); + check_mysql_rc(rc, mysql); + + return OK; +} + struct my_tests_st my_tests[] = { + {"test_conc544", test_conc544, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc490", test_conc490, TEST_CONNECTION_NONE, 0, NULL, NULL}, {"test_gtid", test_gtid, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc496", test_conc496, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},