Commit c94ec9fc authored by Sergei Golubchik's avatar Sergei Golubchik

MDEV-17950 SHOW GRANTS FOR does not work for a user identified with non-existing plugin

Revert the side effect of 7c40996c.
Do not convert password hash to its binary representation when a user
entry is loaded. Do it lazily on the first authenticatation attempt.

As a collateral - force all authentication plugins to follow the
protocol and read_packet at least once before accessing info->username
(username is not available before first client handshake packet is read).

Fix PAM and GSSAPI plugins to behave.
parent 3742f6f9
update mysql.global_priv set priv=json_insert(priv, '$.plugin', 'unix_socket');
flush privileges;
Warnings:
Warning 1524 Plugin 'unix_socket' is not loaded
Warning 1524 Plugin 'unix_socket' is not loaded
Warning 1524 Plugin 'unix_socket' is not loaded
Warning 1524 Plugin 'unix_socket' is not loaded
connect(localhost,USER,,test,MASTER_PORT,MASTER_SOCKET);
ERROR 28000: Access denied for user 'USER'@'localhost' (using password: NO)
ERROR 28000: Access denied for user 'USER'@'localhost' (using password: NO)
ERROR HY000: Plugin 'unix_socket' is not loaded
ERROR HY000: Plugin 'unix_socket' is not loaded
install plugin unix_socket soname 'auth_socket.so';
flush privileges;
connect(localhost,USER,,test,MASTER_PORT,MASTER_SOCKET);
......
......@@ -14,12 +14,12 @@ let $replace=Access denied for user '$USER';
--echo connect(localhost,USER,,test,MASTER_PORT,MASTER_SOCKET);
--replace_result $replace "Access denied for user 'USER'"
--disable_query_log
--error ER_ACCESS_DENIED_ERROR
--error ER_PLUGIN_IS_NOT_LOADED
connect (fail,localhost,$USER);
--enable_query_log
--replace_result $replace "Access denied for user 'USER'"
--error ER_ACCESS_DENIED_ERROR
--error ER_PLUGIN_IS_NOT_LOADED
change_user $USER;
eval install plugin unix_socket soname '$AUTH_SOCKET_SO';
......
......@@ -59,12 +59,9 @@ update mysql.global_priv set priv=json_set(priv, '$.authentication_string', 'bad
update mysql.global_priv set priv=json_set(priv, '$.authentication_string', 'bad') where user='u5';
update mysql.global_priv set priv=json_set(priv, '$.plugin', 'nonexistent') where user='u8';
flush privileges;
Warnings:
Error 1372 Password hash should be a 41-digit hexadecimal number
Error 1372 Password hash should be a 16-digit hexadecimal number
Warning 1524 Plugin 'nonexistent' is not loaded
show create user u1@h;
ERROR 28000: Can't find any matching row in the user table
CREATE USER for u1@h
CREATE USER 'u1'@'h' IDENTIFIED BY PASSWORD 'bad'
show create user u2@h;
CREATE USER for u2@h
CREATE USER 'u2'@'h' IDENTIFIED BY PASSWORD '*975B2CD4FF9AE554FE8AD33168FBFC326D2021DD'
......@@ -75,7 +72,8 @@ show create user u4@h;
CREATE USER for u4@h
CREATE USER 'u4'@'h' IDENTIFIED BY PASSWORD '*975B2CD4FF9AE554FE8AD33168FBFC326D2021DD'
show create user u5@h;
ERROR 28000: Can't find any matching row in the user table
CREATE USER for u5@h
CREATE USER 'u5'@'h' IDENTIFIED BY PASSWORD 'bad'
show create user u6@h;
CREATE USER for u6@h
CREATE USER 'u6'@'h' IDENTIFIED BY PASSWORD '78a302dd267f6044'
......@@ -83,26 +81,24 @@ show create user u7@h;
CREATE USER for u7@h
CREATE USER 'u7'@'h' IDENTIFIED BY PASSWORD '78a302dd267f6044'
show create user u8@h;
ERROR 28000: Can't find any matching row in the user table
CREATE USER for u8@h
CREATE USER 'u8'@'h' IDENTIFIED VIA nonexistent USING '78a302dd267f6044'
grant select on *.* to u1@h;
ERROR 28000: Can't find any matching row in the user table
grant select on *.* to u2@h;
grant select on *.* to u3@h;
grant select on *.* to u4@h;
grant select on *.* to u5@h;
ERROR 28000: Can't find any matching row in the user table
grant select on *.* to u6@h;
grant select on *.* to u7@h;
grant select on *.* to u8@h;
ERROR 28000: Can't find any matching row in the user table
select user,select_priv,plugin,authentication_string from mysql.user where user like 'u_';
User Select_priv plugin authentication_string
u1 N mysql_native_password bad
u1 Y mysql_native_password bad
u2 Y mysql_native_password *975B2CD4FF9AE554FE8AD33168FBFC326D2021DD
u3 Y mysql_native_password *975B2CD4FF9AE554FE8AD33168FBFC326D2021DD
u4 Y mysql_native_password *975B2CD4FF9AE554FE8AD33168FBFC326D2021DD
u5 N mysql_old_password bad
u5 Y mysql_old_password bad
u6 Y mysql_old_password 78a302dd267f6044
u7 Y mysql_old_password 78a302dd267f6044
u8 N nonexistent 78a302dd267f6044
u8 Y nonexistent 78a302dd267f6044
drop user u1@h, u2@h, u3@h, u4@h, u5@h, u6@h, u7@h, u8@h;
......@@ -66,29 +66,21 @@ update mysql.global_priv set priv=json_set(priv, '$.authentication_string', 'bad
update mysql.global_priv set priv=json_set(priv, '$.authentication_string', 'bad') where user='u5';
update mysql.global_priv set priv=json_set(priv, '$.plugin', 'nonexistent') where user='u8';
flush privileges;
# invalid entries are skipped, users don't exist
error ER_PASSWORD_NO_MATCH;
show create user u1@h;
show create user u2@h;
show create user u3@h;
show create user u4@h;
error ER_PASSWORD_NO_MATCH;
show create user u5@h;
show create user u6@h;
show create user u7@h;
error ER_PASSWORD_NO_MATCH;
show create user u8@h;
#grants don't work either
error ER_PASSWORD_NO_MATCH;
grant select on *.* to u1@h;
grant select on *.* to u2@h;
grant select on *.* to u3@h;
grant select on *.* to u4@h;
error ER_PASSWORD_NO_MATCH;
grant select on *.* to u5@h;
grant select on *.* to u6@h;
grant select on *.* to u7@h;
error ER_PASSWORD_NO_MATCH;
grant select on *.* to u8@h;
select user,select_priv,plugin,authentication_string from mysql.user where user like 'u_';
......
......@@ -149,13 +149,11 @@ new_user test_plugin_server new_dest
plug_dest mysql_native_password *939AEE68989794C0F408277411C26055CDF41119
UPDATE mysql.global_priv SET priv=JSON_SET(priv, '$.plugin', 'new_plugin_server') WHERE user='new_user';
FLUSH PRIVILEGES;
Warnings:
Warning 1524 Plugin 'new_plugin_server' is not loaded
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
User plugin authentication_string
new_user new_plugin_server new_dest
plug_dest mysql_native_password *939AEE68989794C0F408277411C26055CDF41119
ERROR 28000: Access denied for user 'new_user'@'localhost' (using password: YES)
ERROR HY000: Plugin 'new_plugin_server' is not loaded
UPDATE mysql.global_priv SET priv=JSON_SET(priv, '$.plugin', 'test_plugin_server') WHERE user='new_user';
UPDATE mysql.global_priv SET user='new_dest' WHERE user='plug_dest';
FLUSH PRIVILEGES;
......
......@@ -141,7 +141,7 @@ FLUSH PRIVILEGES;
--sorted_result
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
--disable_query_log
--error ER_ACCESS_DENIED_ERROR
--error ER_PLUGIN_IS_NOT_LOADED
connect(plug_user,localhost,new_user,new_dest);
--enable_query_log
UPDATE mysql.global_priv SET priv=JSON_SET(priv, '$.plugin', 'test_plugin_server') WHERE user='new_user';
......
......@@ -145,7 +145,7 @@ int plugin_deinit()
}
int auth_server(MYSQL_PLUGIN_VIO *vio,const char *user, size_t userlen, int use_full_name)
int auth_server(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *auth_info)
{
int rc= CR_ERROR; /* return code */
......@@ -157,6 +157,9 @@ int auth_server(MYSQL_PLUGIN_VIO *vio,const char *user, size_t userlen, int use_
gss_name_t client_name;
gss_buffer_desc client_name_buf, input, output;
char *client_name_str;
const char *user= 0;
size_t userlen;
int use_full_name;
/* server acquires credential */
major= gss_acquire_cred(&minor, service_name, GSS_C_INDEFINITE,
......@@ -180,6 +183,21 @@ int auth_server(MYSQL_PLUGIN_VIO *vio,const char *user, size_t userlen, int use_
log_error(0, 0, "fail to read token from client");
goto cleanup;
}
if (!user)
{
if (auth_info->auth_string_length > 0)
{
use_full_name= 1;
user= auth_info->auth_string;
userlen= auth_info->auth_string_length;
}
else
{
use_full_name= 0;
user= auth_info->user_name;
userlen= auth_info->user_name_length;
}
}
input.length= len;
major= gss_accept_sec_context(&minor, &ctxt, cred, &input,
......
......@@ -64,41 +64,11 @@ unsigned long srv_mech;
*/
static int gssapi_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *auth_info)
{
int use_full_name;
const char *user;
int user_len;
/* No user name yet ? Read the client handshake packet with the user name. */
if (auth_info->user_name == 0)
{
unsigned char *pkt;
if (vio->read_packet(vio, &pkt) < 0)
return CR_ERROR;
}
/* Send first packet with target name and mech name */
if (vio->write_packet(vio, (unsigned char *)first_packet, first_packet_len))
{
return CR_ERROR;
}
/* Figure out whether to use full name (as given in IDENTIFIED AS clause)
* or just short username auth_string
*/
if (auth_info->auth_string_length > 0)
{
use_full_name= 1;
user= auth_info->auth_string;
user_len= auth_info->auth_string_length;
}
else
{
use_full_name= 0;
user= auth_info->user_name;
user_len= auth_info->user_name_length;
}
return auth_server(vio, user, user_len, use_full_name);
return auth_server(vio, auth_info);
}
static int initialize_plugin(void *unused)
......
......@@ -48,4 +48,4 @@ extern char *srv_keytab_path;
int plugin_init();
int plugin_deinit();
int auth_server(MYSQL_PLUGIN_VIO *vio, const char *username, size_t username_len, int use_full_name);
int auth_server(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *auth_info);
......@@ -140,7 +140,7 @@ static int get_client_name_from_context(CtxtHandle *ctxt,
}
int auth_server(MYSQL_PLUGIN_VIO *vio, const char *user, size_t user_len, int compare_full_name)
int auth_server(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *auth_info)
{
int ret;
SECURITY_STATUS sspi_ret;
......@@ -155,6 +155,8 @@ int auth_server(MYSQL_PLUGIN_VIO *vio, const char *user, size_t user_len, int co
SecBuffer outbuf;
void* out= NULL;
char client_name[MYSQL_USERNAME_LENGTH + 1];
const char *user= 0;
int compare_full_name;
ret= CR_ERROR;
SecInvalidateHandle(&cred);
......@@ -207,6 +209,19 @@ int auth_server(MYSQL_PLUGIN_VIO *vio, const char *user, size_t user_len, int co
log_error(SEC_E_OK, "communication error(read)");
goto cleanup;
}
if (!user)
{
if (auth_info->auth_string_length > 0)
{
compare_full_name= 1;
user= auth_info->auth_string;
}
else
{
compare_full_name= 0;
user= auth_info->user_name;
}
}
inbuf.cbBuffer= len;
outbuf.cbBuffer= SSPI_MAX_TOKEN_SIZE;
sspi_ret= AcceptSecurityContext(
......
......@@ -36,8 +36,8 @@ static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
{
int p_to_c[2], c_to_p[2]; /* Parent-to-child and child-to-parent pipes. */
pid_t proc_id;
int result= CR_ERROR;
unsigned char field;
int result= CR_ERROR, pkt_len;
unsigned char field, *pkt;
PAM_DEBUG((stderr, "PAM: opening pipes.\n"));
if (pipe(p_to_c) < 0 || pipe(c_to_p) < 0)
......@@ -96,6 +96,14 @@ static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
close(c_to_p[1]) < 0)
goto error_ret;
/* no user name yet ? read the client handshake packet with the user name */
if (info->user_name == 0)
{
if ((pkt_len= vio->read_packet(vio, &pkt) < 0))
return CR_ERROR;
}
else
pkt= NULL;
PAM_DEBUG((stderr, "PAM: parent sends user data [%s], [%s].\n",
info->user_name, info->auth_string));
......@@ -140,23 +148,27 @@ static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
{
unsigned char buf[10240];
int buf_len;
unsigned char *pkt;
PAM_DEBUG((stderr, "PAM: getting CONV string.\n"));
if ((buf_len= read_string(c_to_p[0], (char *) buf, sizeof(buf))) < 0)
goto error_ret;
PAM_DEBUG((stderr, "PAM: sending CONV string.\n"));
if (vio->write_packet(vio, buf, buf_len))
goto error_ret;
if (!pkt || (buf[0] >> 1) != 2)
{
PAM_DEBUG((stderr, "PAM: sending CONV string.\n"));
if (vio->write_packet(vio, buf, buf_len))
goto error_ret;
PAM_DEBUG((stderr, "PAM: reading CONV answer.\n"));
if ((buf_len= vio->read_packet(vio, &pkt)) < 0)
goto error_ret;
PAM_DEBUG((stderr, "PAM: reading CONV answer.\n"));
if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
goto error_ret;
}
PAM_DEBUG((stderr, "PAM: answering CONV.\n"));
if (write_string(p_to_c[1], pkt, buf_len))
if (write_string(p_to_c[1], pkt, pkt_len))
goto error_ret;
pkt= NULL;
}
break;
......
......@@ -17,13 +17,21 @@
#include <mysql/plugin_auth.h>
struct param {
unsigned char buf[10240], *ptr;
unsigned char buf[10240], *ptr, *cached;
int cached_len;
MYSQL_PLUGIN_VIO *vio;
};
static int roundtrip(struct param *param, const unsigned char *buf,
int buf_len, unsigned char **pkt)
{
if (param->cached && (buf[0] >> 1) == 2)
{
*pkt= param->cached;
param->cached= NULL;
return param->cached_len;
}
param->cached= NULL;
if (param->vio->write_packet(param->vio, buf, buf_len))
return -1;
return param->vio->read_packet(param->vio, pkt);
......@@ -35,6 +43,16 @@ static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
{
struct param param;
param.vio = vio;
/* no user name yet ? read the client handshake packet with the user name */
if (info->user_name == 0)
{
if ((param.cached_len= vio->read_packet(vio, &param.cached) < 0))
return CR_ERROR;
}
else
param.cached= NULL;
return pam_auth_base(&param, info);
}
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment