MDEV-17950 SHOW GRANTS FOR does not work for a user identified with non-existing plugin
Revert the side effect of 7c40996cc866. 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.
This commit is contained in:
parent
3742f6f9aa
commit
c94ec9fc67
@ -1,13 +1,8 @@
|
|||||||
update mysql.global_priv set priv=json_insert(priv, '$.plugin', 'unix_socket');
|
update mysql.global_priv set priv=json_insert(priv, '$.plugin', 'unix_socket');
|
||||||
flush privileges;
|
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);
|
connect(localhost,USER,,test,MASTER_PORT,MASTER_SOCKET);
|
||||||
ERROR 28000: Access denied for user 'USER'@'localhost' (using password: NO)
|
ERROR HY000: Plugin 'unix_socket' is not loaded
|
||||||
ERROR 28000: Access denied for user 'USER'@'localhost' (using password: NO)
|
ERROR HY000: Plugin 'unix_socket' is not loaded
|
||||||
install plugin unix_socket soname 'auth_socket.so';
|
install plugin unix_socket soname 'auth_socket.so';
|
||||||
flush privileges;
|
flush privileges;
|
||||||
connect(localhost,USER,,test,MASTER_PORT,MASTER_SOCKET);
|
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);
|
--echo connect(localhost,USER,,test,MASTER_PORT,MASTER_SOCKET);
|
||||||
--replace_result $replace "Access denied for user 'USER'"
|
--replace_result $replace "Access denied for user 'USER'"
|
||||||
--disable_query_log
|
--disable_query_log
|
||||||
--error ER_ACCESS_DENIED_ERROR
|
--error ER_PLUGIN_IS_NOT_LOADED
|
||||||
connect (fail,localhost,$USER);
|
connect (fail,localhost,$USER);
|
||||||
--enable_query_log
|
--enable_query_log
|
||||||
|
|
||||||
--replace_result $replace "Access denied for user 'USER'"
|
--replace_result $replace "Access denied for user 'USER'"
|
||||||
--error ER_ACCESS_DENIED_ERROR
|
--error ER_PLUGIN_IS_NOT_LOADED
|
||||||
change_user $USER;
|
change_user $USER;
|
||||||
|
|
||||||
eval install plugin unix_socket soname '$AUTH_SOCKET_SO';
|
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, '$.authentication_string', 'bad') where user='u5';
|
||||||
update mysql.global_priv set priv=json_set(priv, '$.plugin', 'nonexistent') where user='u8';
|
update mysql.global_priv set priv=json_set(priv, '$.plugin', 'nonexistent') where user='u8';
|
||||||
flush privileges;
|
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;
|
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;
|
show create user u2@h;
|
||||||
CREATE USER for u2@h
|
CREATE USER for u2@h
|
||||||
CREATE USER 'u2'@'h' IDENTIFIED BY PASSWORD '*975B2CD4FF9AE554FE8AD33168FBFC326D2021DD'
|
CREATE USER 'u2'@'h' IDENTIFIED BY PASSWORD '*975B2CD4FF9AE554FE8AD33168FBFC326D2021DD'
|
||||||
@ -75,7 +72,8 @@ show create user u4@h;
|
|||||||
CREATE USER for u4@h
|
CREATE USER for u4@h
|
||||||
CREATE USER 'u4'@'h' IDENTIFIED BY PASSWORD '*975B2CD4FF9AE554FE8AD33168FBFC326D2021DD'
|
CREATE USER 'u4'@'h' IDENTIFIED BY PASSWORD '*975B2CD4FF9AE554FE8AD33168FBFC326D2021DD'
|
||||||
show create user u5@h;
|
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;
|
show create user u6@h;
|
||||||
CREATE USER for u6@h
|
CREATE USER for u6@h
|
||||||
CREATE USER 'u6'@'h' IDENTIFIED BY PASSWORD '78a302dd267f6044'
|
CREATE USER 'u6'@'h' IDENTIFIED BY PASSWORD '78a302dd267f6044'
|
||||||
@ -83,26 +81,24 @@ show create user u7@h;
|
|||||||
CREATE USER for u7@h
|
CREATE USER for u7@h
|
||||||
CREATE USER 'u7'@'h' IDENTIFIED BY PASSWORD '78a302dd267f6044'
|
CREATE USER 'u7'@'h' IDENTIFIED BY PASSWORD '78a302dd267f6044'
|
||||||
show create user u8@h;
|
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;
|
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 u2@h;
|
||||||
grant select on *.* to u3@h;
|
grant select on *.* to u3@h;
|
||||||
grant select on *.* to u4@h;
|
grant select on *.* to u4@h;
|
||||||
grant select on *.* to u5@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 u6@h;
|
||||||
grant select on *.* to u7@h;
|
grant select on *.* to u7@h;
|
||||||
grant select on *.* to u8@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_';
|
select user,select_priv,plugin,authentication_string from mysql.user where user like 'u_';
|
||||||
User Select_priv plugin authentication_string
|
User Select_priv plugin authentication_string
|
||||||
u1 N mysql_native_password bad
|
u1 Y mysql_native_password bad
|
||||||
u2 Y mysql_native_password *975B2CD4FF9AE554FE8AD33168FBFC326D2021DD
|
u2 Y mysql_native_password *975B2CD4FF9AE554FE8AD33168FBFC326D2021DD
|
||||||
u3 Y mysql_native_password *975B2CD4FF9AE554FE8AD33168FBFC326D2021DD
|
u3 Y mysql_native_password *975B2CD4FF9AE554FE8AD33168FBFC326D2021DD
|
||||||
u4 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
|
u6 Y mysql_old_password 78a302dd267f6044
|
||||||
u7 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;
|
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, '$.authentication_string', 'bad') where user='u5';
|
||||||
update mysql.global_priv set priv=json_set(priv, '$.plugin', 'nonexistent') where user='u8';
|
update mysql.global_priv set priv=json_set(priv, '$.plugin', 'nonexistent') where user='u8';
|
||||||
flush privileges;
|
flush privileges;
|
||||||
# invalid entries are skipped, users don't exist
|
|
||||||
error ER_PASSWORD_NO_MATCH;
|
|
||||||
show create user u1@h;
|
show create user u1@h;
|
||||||
show create user u2@h;
|
show create user u2@h;
|
||||||
show create user u3@h;
|
show create user u3@h;
|
||||||
show create user u4@h;
|
show create user u4@h;
|
||||||
error ER_PASSWORD_NO_MATCH;
|
|
||||||
show create user u5@h;
|
show create user u5@h;
|
||||||
show create user u6@h;
|
show create user u6@h;
|
||||||
show create user u7@h;
|
show create user u7@h;
|
||||||
error ER_PASSWORD_NO_MATCH;
|
|
||||||
show create user u8@h;
|
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 u1@h;
|
||||||
grant select on *.* to u2@h;
|
grant select on *.* to u2@h;
|
||||||
grant select on *.* to u3@h;
|
grant select on *.* to u3@h;
|
||||||
grant select on *.* to u4@h;
|
grant select on *.* to u4@h;
|
||||||
error ER_PASSWORD_NO_MATCH;
|
|
||||||
grant select on *.* to u5@h;
|
grant select on *.* to u5@h;
|
||||||
grant select on *.* to u6@h;
|
grant select on *.* to u6@h;
|
||||||
grant select on *.* to u7@h;
|
grant select on *.* to u7@h;
|
||||||
error ER_PASSWORD_NO_MATCH;
|
|
||||||
grant select on *.* to u8@h;
|
grant select on *.* to u8@h;
|
||||||
select user,select_priv,plugin,authentication_string from mysql.user where user like 'u_';
|
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
|
plug_dest mysql_native_password *939AEE68989794C0F408277411C26055CDF41119
|
||||||
UPDATE mysql.global_priv SET priv=JSON_SET(priv, '$.plugin', 'new_plugin_server') WHERE user='new_user';
|
UPDATE mysql.global_priv SET priv=JSON_SET(priv, '$.plugin', 'new_plugin_server') WHERE user='new_user';
|
||||||
FLUSH PRIVILEGES;
|
FLUSH PRIVILEGES;
|
||||||
Warnings:
|
|
||||||
Warning 1524 Plugin 'new_plugin_server' is not loaded
|
|
||||||
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
|
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
|
||||||
User plugin authentication_string
|
User plugin authentication_string
|
||||||
new_user new_plugin_server new_dest
|
new_user new_plugin_server new_dest
|
||||||
plug_dest mysql_native_password *939AEE68989794C0F408277411C26055CDF41119
|
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 priv=JSON_SET(priv, '$.plugin', 'test_plugin_server') WHERE user='new_user';
|
||||||
UPDATE mysql.global_priv SET user='new_dest' WHERE user='plug_dest';
|
UPDATE mysql.global_priv SET user='new_dest' WHERE user='plug_dest';
|
||||||
FLUSH PRIVILEGES;
|
FLUSH PRIVILEGES;
|
||||||
|
@ -141,7 +141,7 @@ FLUSH PRIVILEGES;
|
|||||||
--sorted_result
|
--sorted_result
|
||||||
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
|
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
|
||||||
--disable_query_log
|
--disable_query_log
|
||||||
--error ER_ACCESS_DENIED_ERROR
|
--error ER_PLUGIN_IS_NOT_LOADED
|
||||||
connect(plug_user,localhost,new_user,new_dest);
|
connect(plug_user,localhost,new_user,new_dest);
|
||||||
--enable_query_log
|
--enable_query_log
|
||||||
UPDATE mysql.global_priv SET priv=JSON_SET(priv, '$.plugin', 'test_plugin_server') WHERE user='new_user';
|
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 */
|
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_name_t client_name;
|
||||||
gss_buffer_desc client_name_buf, input, output;
|
gss_buffer_desc client_name_buf, input, output;
|
||||||
char *client_name_str;
|
char *client_name_str;
|
||||||
|
const char *user= 0;
|
||||||
|
size_t userlen;
|
||||||
|
int use_full_name;
|
||||||
|
|
||||||
/* server acquires credential */
|
/* server acquires credential */
|
||||||
major= gss_acquire_cred(&minor, service_name, GSS_C_INDEFINITE,
|
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");
|
log_error(0, 0, "fail to read token from client");
|
||||||
goto cleanup;
|
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;
|
input.length= len;
|
||||||
major= gss_accept_sec_context(&minor, &ctxt, cred, &input,
|
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)
|
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 */
|
/* Send first packet with target name and mech name */
|
||||||
if (vio->write_packet(vio, (unsigned char *)first_packet, first_packet_len))
|
if (vio->write_packet(vio, (unsigned char *)first_packet, first_packet_len))
|
||||||
{
|
|
||||||
return CR_ERROR;
|
return CR_ERROR;
|
||||||
}
|
|
||||||
|
|
||||||
/* Figure out whether to use full name (as given in IDENTIFIED AS clause)
|
return auth_server(vio, auth_info);
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int initialize_plugin(void *unused)
|
static int initialize_plugin(void *unused)
|
||||||
|
@ -48,4 +48,4 @@ extern char *srv_keytab_path;
|
|||||||
int plugin_init();
|
int plugin_init();
|
||||||
int plugin_deinit();
|
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;
|
int ret;
|
||||||
SECURITY_STATUS sspi_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;
|
SecBuffer outbuf;
|
||||||
void* out= NULL;
|
void* out= NULL;
|
||||||
char client_name[MYSQL_USERNAME_LENGTH + 1];
|
char client_name[MYSQL_USERNAME_LENGTH + 1];
|
||||||
|
const char *user= 0;
|
||||||
|
int compare_full_name;
|
||||||
|
|
||||||
ret= CR_ERROR;
|
ret= CR_ERROR;
|
||||||
SecInvalidateHandle(&cred);
|
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)");
|
log_error(SEC_E_OK, "communication error(read)");
|
||||||
goto cleanup;
|
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;
|
inbuf.cbBuffer= len;
|
||||||
outbuf.cbBuffer= SSPI_MAX_TOKEN_SIZE;
|
outbuf.cbBuffer= SSPI_MAX_TOKEN_SIZE;
|
||||||
sspi_ret= AcceptSecurityContext(
|
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. */
|
int p_to_c[2], c_to_p[2]; /* Parent-to-child and child-to-parent pipes. */
|
||||||
pid_t proc_id;
|
pid_t proc_id;
|
||||||
int result= CR_ERROR;
|
int result= CR_ERROR, pkt_len;
|
||||||
unsigned char field;
|
unsigned char field, *pkt;
|
||||||
|
|
||||||
PAM_DEBUG((stderr, "PAM: opening pipes.\n"));
|
PAM_DEBUG((stderr, "PAM: opening pipes.\n"));
|
||||||
if (pipe(p_to_c) < 0 || pipe(c_to_p) < 0)
|
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)
|
close(c_to_p[1]) < 0)
|
||||||
goto error_ret;
|
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",
|
PAM_DEBUG((stderr, "PAM: parent sends user data [%s], [%s].\n",
|
||||||
info->user_name, info->auth_string));
|
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];
|
unsigned char buf[10240];
|
||||||
int buf_len;
|
int buf_len;
|
||||||
unsigned char *pkt;
|
|
||||||
|
|
||||||
PAM_DEBUG((stderr, "PAM: getting CONV string.\n"));
|
PAM_DEBUG((stderr, "PAM: getting CONV string.\n"));
|
||||||
if ((buf_len= read_string(c_to_p[0], (char *) buf, sizeof(buf))) < 0)
|
if ((buf_len= read_string(c_to_p[0], (char *) buf, sizeof(buf))) < 0)
|
||||||
goto error_ret;
|
goto error_ret;
|
||||||
|
|
||||||
PAM_DEBUG((stderr, "PAM: sending CONV string.\n"));
|
if (!pkt || (buf[0] >> 1) != 2)
|
||||||
if (vio->write_packet(vio, buf, buf_len))
|
{
|
||||||
goto error_ret;
|
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"));
|
PAM_DEBUG((stderr, "PAM: reading CONV answer.\n"));
|
||||||
if ((buf_len= vio->read_packet(vio, &pkt)) < 0)
|
if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
|
||||||
goto error_ret;
|
goto error_ret;
|
||||||
|
}
|
||||||
|
|
||||||
PAM_DEBUG((stderr, "PAM: answering CONV.\n"));
|
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;
|
goto error_ret;
|
||||||
|
|
||||||
|
pkt= NULL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -17,13 +17,21 @@
|
|||||||
#include <mysql/plugin_auth.h>
|
#include <mysql/plugin_auth.h>
|
||||||
|
|
||||||
struct param {
|
struct param {
|
||||||
unsigned char buf[10240], *ptr;
|
unsigned char buf[10240], *ptr, *cached;
|
||||||
|
int cached_len;
|
||||||
MYSQL_PLUGIN_VIO *vio;
|
MYSQL_PLUGIN_VIO *vio;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int roundtrip(struct param *param, const unsigned char *buf,
|
static int roundtrip(struct param *param, const unsigned char *buf,
|
||||||
int buf_len, unsigned char **pkt)
|
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))
|
if (param->vio->write_packet(param->vio, buf, buf_len))
|
||||||
return -1;
|
return -1;
|
||||||
return param->vio->read_packet(param->vio, pkt);
|
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;
|
struct param param;
|
||||||
param.vio = vio;
|
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, ¶m.cached) < 0))
|
||||||
|
return CR_ERROR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
param.cached= NULL;
|
||||||
|
|
||||||
return pam_auth_base(¶m, info);
|
return pam_auth_base(¶m, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
159
sql/sql_acl.cc
159
sql/sql_acl.cc
@ -170,7 +170,8 @@ public:
|
|||||||
else
|
else
|
||||||
dst->plugin= safe_lexcstrdup_root(root, plugin);
|
dst->plugin= safe_lexcstrdup_root(root, plugin);
|
||||||
dst->auth_string= safe_lexcstrdup_root(root, auth_string);
|
dst->auth_string= safe_lexcstrdup_root(root, auth_string);
|
||||||
dst->salt= safe_lexcstrdup_root(root, salt);
|
if (salt.str)
|
||||||
|
dst->salt= safe_lexcstrdup_root(root, salt);
|
||||||
dst->host.hostname= safe_strdup_root(root, host.hostname);
|
dst->host.hostname= safe_strdup_root(root, host.hostname);
|
||||||
dst->default_rolename= safe_lexcstrdup_root(root, default_rolename);
|
dst->default_rolename= safe_lexcstrdup_root(root, default_rolename);
|
||||||
bzero(&dst->role_grants, sizeof(role_grants));
|
bzero(&dst->role_grants, sizeof(role_grants));
|
||||||
@ -1781,6 +1782,26 @@ static bool validate_password(THD *thd, const LEX_CSTRING &user,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int set_user_salt(ACL_USER *acl_user, plugin_ref plugin)
|
||||||
|
{
|
||||||
|
st_mysql_auth *auth= (st_mysql_auth *) plugin_decl(plugin)->info;
|
||||||
|
if (auth->interface_version >= 0x0202 && acl_user->auth_string.length &&
|
||||||
|
auth->preprocess_hash)
|
||||||
|
{
|
||||||
|
uchar buf[MAX_SCRAMBLE_LENGTH];
|
||||||
|
size_t len= sizeof(buf);
|
||||||
|
if (auth->preprocess_hash(acl_user->auth_string.str,
|
||||||
|
acl_user->auth_string.length, buf, &len))
|
||||||
|
return 1; // ER_PASSWD_LENGTH?
|
||||||
|
acl_user->salt.str= (char*)memdup_root(&acl_memroot, buf, len);
|
||||||
|
acl_user->salt.length= len;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
acl_user->salt= acl_user->auth_string;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Fills in ACL_USER::auth_string and ACL_USER::salt fields, as needed
|
Fills in ACL_USER::auth_string and ACL_USER::salt fields, as needed
|
||||||
|
|
||||||
@ -1789,11 +1810,8 @@ static bool validate_password(THD *thd, const LEX_CSTRING &user,
|
|||||||
|
|
||||||
Fails if the plain-text password fails validation, if the plugin is
|
Fails if the plain-text password fails validation, if the plugin is
|
||||||
not loaded, if the auth_string is invalid.
|
not loaded, if the auth_string is invalid.
|
||||||
|
|
||||||
Using NULL for a password disables validation
|
|
||||||
(needed for loading from mysql.user table).
|
|
||||||
*/
|
*/
|
||||||
static int set_user_auth(THD *thd, ACL_USER *acl_user, const LEX_CSTRING *pwtext)
|
static int set_user_auth(THD *thd, ACL_USER *acl_user, const LEX_CSTRING &pwtext)
|
||||||
{
|
{
|
||||||
const char *plugin_name= acl_user->plugin.str;
|
const char *plugin_name= acl_user->plugin.str;
|
||||||
bool unlock_plugin= false;
|
bool unlock_plugin= false;
|
||||||
@ -1813,49 +1831,32 @@ static int set_user_auth(THD *thd, ACL_USER *acl_user, const LEX_CSTRING *pwtext
|
|||||||
st_mysql_auth *auth= (st_mysql_auth *) plugin_decl(plugin)->info;
|
st_mysql_auth *auth= (st_mysql_auth *) plugin_decl(plugin)->info;
|
||||||
if (auth->interface_version >= 0x0202)
|
if (auth->interface_version >= 0x0202)
|
||||||
{
|
{
|
||||||
if (pwtext)
|
if (auth->hash_password &&
|
||||||
|
validate_password(thd, acl_user->user, pwtext,
|
||||||
|
acl_user->auth_string.length))
|
||||||
|
goto end;
|
||||||
|
if (pwtext.length)
|
||||||
{
|
{
|
||||||
if (auth->hash_password &&
|
if (auth->hash_password)
|
||||||
validate_password(thd, acl_user->user, *pwtext,
|
|
||||||
acl_user->auth_string.length))
|
|
||||||
goto end;
|
|
||||||
if (pwtext->length)
|
|
||||||
{
|
{
|
||||||
if (auth->hash_password)
|
char buf[MAX_SCRAMBLE_LENGTH];
|
||||||
{
|
size_t len= sizeof(buf) - 1;
|
||||||
char buf[MAX_SCRAMBLE_LENGTH];
|
if (auth->hash_password(pwtext.str, pwtext.length, buf, &len))
|
||||||
size_t len= sizeof(buf) - 1;
|
goto end; // OOM?
|
||||||
if (auth->hash_password(pwtext->str, pwtext->length, buf, &len))
|
buf[len] = 0;
|
||||||
goto end; // OOM?
|
acl_user->auth_string.str= (char*)memdup_root(&acl_memroot, buf, len+1);
|
||||||
buf[len] = 0;
|
acl_user->auth_string.length= len;
|
||||||
acl_user->auth_string.str= (char*)memdup_root(&acl_memroot, buf, len+1);
|
|
||||||
acl_user->auth_string.length= len;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
|
||||||
ER_SET_PASSWORD_AUTH_PLUGIN,
|
|
||||||
ER_THD(thd, ER_SET_PASSWORD_AUTH_PLUGIN),
|
|
||||||
acl_user->plugin.str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (acl_user->auth_string.length)
|
|
||||||
{
|
|
||||||
if (auth->preprocess_hash)
|
|
||||||
{
|
|
||||||
uchar buf[MAX_SCRAMBLE_LENGTH];
|
|
||||||
size_t len= sizeof(buf);
|
|
||||||
if (auth->preprocess_hash(acl_user->auth_string.str,
|
|
||||||
acl_user->auth_string.length, buf, &len))
|
|
||||||
goto end; // ER_PASSWD_LENGTH?
|
|
||||||
acl_user->salt.str= (char*)memdup_root(&acl_memroot, buf, len);
|
|
||||||
acl_user->salt.length= len;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
acl_user->salt= acl_user->auth_string;
|
{
|
||||||
|
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||||
|
ER_SET_PASSWORD_AUTH_PLUGIN,
|
||||||
|
ER_THD(thd, ER_SET_PASSWORD_AUTH_PLUGIN),
|
||||||
|
acl_user->plugin.str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (set_user_salt(acl_user, plugin))
|
||||||
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
res= 0;
|
res= 0;
|
||||||
@ -1865,6 +1866,34 @@ end:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Lazily computes user's salt from the password hash
|
||||||
|
*/
|
||||||
|
static bool set_user_salt_if_needed(ACL_USER *user_copy, plugin_ref plugin)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(!strcasecmp(user_copy->plugin.str, plugin_name(plugin)->str));
|
||||||
|
|
||||||
|
if (user_copy->salt.str)
|
||||||
|
return 0; // already done
|
||||||
|
|
||||||
|
if (set_user_salt(user_copy, plugin))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
mysql_mutex_lock(&acl_cache->lock);
|
||||||
|
ACL_USER *user= find_user_exact(user_copy->host.hostname, user_copy->user.str);
|
||||||
|
// make sure the user wasn't altered or dropped meanwhile
|
||||||
|
if (user && !user->salt.str &&
|
||||||
|
user->plugin.length == user_copy->plugin.length &&
|
||||||
|
user->auth_string.length == user_copy->auth_string.length &&
|
||||||
|
!memcmp(user->plugin.str, user_copy->plugin.str, user->plugin.length) &&
|
||||||
|
!memcmp(user->auth_string.str, user_copy->auth_string.str, user->auth_string.length))
|
||||||
|
user->salt= user_copy->salt;
|
||||||
|
mysql_mutex_unlock(&acl_cache->lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Fix ACL::plugin pointer to point to a hard-coded string, if appropriate
|
Fix ACL::plugin pointer to point to a hard-coded string, if appropriate
|
||||||
|
|
||||||
@ -2128,12 +2157,6 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
|
|||||||
|
|
||||||
user.default_rolename.str= user_table.get_default_role(&acl_memroot);
|
user.default_rolename.str= user_table.get_default_role(&acl_memroot);
|
||||||
user.default_rolename.length= safe_strlen(user.default_rolename.str);
|
user.default_rolename.length= safe_strlen(user.default_rolename.str);
|
||||||
|
|
||||||
if (set_user_auth(thd, &user, NULL))
|
|
||||||
{
|
|
||||||
thd->clear_error(); // the warning is still issued
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
push_new_user(user);
|
push_new_user(user);
|
||||||
}
|
}
|
||||||
@ -2852,7 +2875,7 @@ static int acl_user_update(THD *thd, ACL_USER *acl_user, const ACL_USER *from,
|
|||||||
acl_user->hostname_length= combo.host.length;
|
acl_user->hostname_length= combo.host.length;
|
||||||
acl_user->sort= get_sort(2, acl_user->host.hostname, acl_user->user.str);
|
acl_user->sort= get_sort(2, acl_user->host.hostname, acl_user->user.str);
|
||||||
acl_user->plugin= native_password_plugin_name;
|
acl_user->plugin= native_password_plugin_name;
|
||||||
acl_user->salt= acl_user->auth_string= empty_clex_str;
|
acl_user->auth_string= empty_clex_str;
|
||||||
my_init_dynamic_array(&acl_user->role_grants, sizeof(ACL_USER *),
|
my_init_dynamic_array(&acl_user->role_grants, sizeof(ACL_USER *),
|
||||||
0, 8, MYF(0));
|
0, 8, MYF(0));
|
||||||
}
|
}
|
||||||
@ -2863,7 +2886,7 @@ static int acl_user_update(THD *thd, ACL_USER *acl_user, const ACL_USER *from,
|
|||||||
acl_user->auth_string= safe_lexcstrdup_root(&acl_memroot, combo.auth);
|
acl_user->auth_string= safe_lexcstrdup_root(&acl_memroot, combo.auth);
|
||||||
if (fix_user_plugin_ptr(acl_user))
|
if (fix_user_plugin_ptr(acl_user))
|
||||||
acl_user->plugin= safe_lexcstrdup_root(&acl_memroot, combo.plugin);
|
acl_user->plugin= safe_lexcstrdup_root(&acl_memroot, combo.plugin);
|
||||||
if (set_user_auth(thd, acl_user, &combo.pwtext))
|
if (set_user_auth(thd, acl_user, combo.pwtext))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
acl_user->access= privileges;
|
acl_user->access= privileges;
|
||||||
@ -3429,7 +3452,7 @@ bool change_password(THD *thd, LEX_USER *user)
|
|||||||
}
|
}
|
||||||
|
|
||||||
acl_user->auth_string= safe_lexcstrdup_root(&acl_memroot, user->auth);
|
acl_user->auth_string= safe_lexcstrdup_root(&acl_memroot, user->auth);
|
||||||
if (set_user_auth(thd, acl_user, &user->pwtext))
|
if (set_user_auth(thd, acl_user, user->pwtext))
|
||||||
{
|
{
|
||||||
mysql_mutex_unlock(&acl_cache->lock);
|
mysql_mutex_unlock(&acl_cache->lock);
|
||||||
goto end;
|
goto end;
|
||||||
@ -11275,10 +11298,10 @@ static int show_database_grants(THD *thd, SHOW_VAR *var, char *buff,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
static bool set_user_salt_if_needed(ACL_USER *, plugin_ref)
|
||||||
|
{ return 0; }
|
||||||
bool check_grant(THD *, ulong, TABLE_LIST *, bool, uint, bool)
|
bool check_grant(THD *, ulong, TABLE_LIST *, bool, uint, bool)
|
||||||
{
|
{ return 0; }
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif /*NO_EMBEDDED_ACCESS_CHECKS */
|
#endif /*NO_EMBEDDED_ACCESS_CHECKS */
|
||||||
|
|
||||||
SHOW_VAR acl_statistics[] = {
|
SHOW_VAR acl_statistics[] = {
|
||||||
@ -12432,12 +12455,6 @@ static bool find_mpvio_user(MPVIO_EXT *mpvio)
|
|||||||
DBUG_RETURN (1);
|
DBUG_RETURN (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
mpvio->auth_info.user_name= sctx->user;
|
|
||||||
mpvio->auth_info.user_name_length= (uint)strlen(sctx->user);
|
|
||||||
mpvio->auth_info.auth_string= mpvio->acl_user->salt.str;
|
|
||||||
mpvio->auth_info.auth_string_length= (unsigned long) mpvio->acl_user->salt.length;
|
|
||||||
strmake_buf(mpvio->auth_info.authenticated_as, mpvio->acl_user->user.str);
|
|
||||||
|
|
||||||
DBUG_PRINT("info", ("exit: user=%s, auth_string=%s, authenticated as=%s"
|
DBUG_PRINT("info", ("exit: user=%s, auth_string=%s, authenticated as=%s"
|
||||||
"plugin=%s",
|
"plugin=%s",
|
||||||
mpvio->auth_info.user_name,
|
mpvio->auth_info.user_name,
|
||||||
@ -12609,8 +12626,7 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((thd->client_capabilities & CLIENT_CONNECT_ATTRS) &&
|
if ((thd->client_capabilities & CLIENT_CONNECT_ATTRS) &&
|
||||||
read_client_connect_attrs(&next_field, end,
|
read_client_connect_attrs(&next_field, end, thd->charset()))
|
||||||
thd->charset()))
|
|
||||||
{
|
{
|
||||||
my_message(ER_UNKNOWN_COM_ERROR, ER_THD(thd, ER_UNKNOWN_COM_ERROR),
|
my_message(ER_UNKNOWN_COM_ERROR, ER_THD(thd, ER_UNKNOWN_COM_ERROR),
|
||||||
MYF(0));
|
MYF(0));
|
||||||
@ -12970,7 +12986,7 @@ static int server_mpvio_write_packet(MYSQL_PLUGIN_VIO *param,
|
|||||||
*/
|
*/
|
||||||
static int server_mpvio_read_packet(MYSQL_PLUGIN_VIO *param, uchar **buf)
|
static int server_mpvio_read_packet(MYSQL_PLUGIN_VIO *param, uchar **buf)
|
||||||
{
|
{
|
||||||
MPVIO_EXT *mpvio= (MPVIO_EXT *) param;
|
MPVIO_EXT * const mpvio= (MPVIO_EXT *) param;
|
||||||
ulong pkt_len;
|
ulong pkt_len;
|
||||||
DBUG_ENTER("server_mpvio_read_packet");
|
DBUG_ENTER("server_mpvio_read_packet");
|
||||||
if (mpvio->packets_written == 0)
|
if (mpvio->packets_written == 0)
|
||||||
@ -13001,11 +13017,11 @@ static int server_mpvio_read_packet(MYSQL_PLUGIN_VIO *param, uchar **buf)
|
|||||||
client_auth_plugin) == 0)
|
client_auth_plugin) == 0)
|
||||||
{
|
{
|
||||||
mpvio->status= MPVIO_EXT::FAILURE;
|
mpvio->status= MPVIO_EXT::FAILURE;
|
||||||
|
pkt_len= mpvio->cached_client_reply.pkt_len;
|
||||||
*buf= (uchar*) mpvio->cached_client_reply.pkt;
|
*buf= (uchar*) mpvio->cached_client_reply.pkt;
|
||||||
mpvio->cached_client_reply.pkt= 0;
|
mpvio->cached_client_reply.pkt= 0;
|
||||||
mpvio->packets_read++;
|
mpvio->packets_read++;
|
||||||
|
goto done;
|
||||||
DBUG_RETURN ((int) mpvio->cached_client_reply.pkt_len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -13039,6 +13055,16 @@ static int server_mpvio_read_packet(MYSQL_PLUGIN_VIO *param, uchar **buf)
|
|||||||
else
|
else
|
||||||
*buf= mpvio->auth_info.thd->net.read_pos;
|
*buf= mpvio->auth_info.thd->net.read_pos;
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (set_user_salt_if_needed(mpvio->acl_user, mpvio->plugin))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
mpvio->auth_info.user_name= mpvio->auth_info.thd->security_ctx->user;
|
||||||
|
mpvio->auth_info.user_name_length= (uint)strlen(mpvio->auth_info.user_name);
|
||||||
|
mpvio->auth_info.auth_string= mpvio->acl_user->salt.str;
|
||||||
|
mpvio->auth_info.auth_string_length= (ulong) mpvio->acl_user->salt.length;
|
||||||
|
strmake_buf(mpvio->auth_info.authenticated_as, mpvio->acl_user->user.str);
|
||||||
|
|
||||||
DBUG_RETURN((int)pkt_len);
|
DBUG_RETURN((int)pkt_len);
|
||||||
|
|
||||||
err:
|
err:
|
||||||
@ -13179,6 +13205,7 @@ static int do_auth_once(THD *thd, const LEX_CSTRING *auth_plugin_name,
|
|||||||
plugin_ref plugin= get_auth_plugin(thd, *auth_plugin_name, &unlock_plugin);
|
plugin_ref plugin= get_auth_plugin(thd, *auth_plugin_name, &unlock_plugin);
|
||||||
|
|
||||||
mpvio->plugin= plugin;
|
mpvio->plugin= plugin;
|
||||||
|
mpvio->auth_info.user_name= NULL;
|
||||||
old_status= mpvio->status;
|
old_status= mpvio->status;
|
||||||
|
|
||||||
if (plugin)
|
if (plugin)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user