Commit c776f5ac authored by unknown's avatar unknown

Client attributes

parent dd733967
......@@ -1359,6 +1359,9 @@ sig_handler handle_sigint(int sig)
}
kill_mysql= mysql_init(kill_mysql);
mysql_options(kill_mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
mysql_options4(kill_mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
"program_name", "mysql");
if (!mysql_real_connect(kill_mysql,current_host, current_user, opt_password,
"", opt_mysql_port, opt_mysql_unix_port,0))
{
......@@ -4606,6 +4609,9 @@ sql_real_connect(char *host,char *database,char *user,char *password,
if (opt_default_auth && *opt_default_auth)
mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
mysql_options(&mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
mysql_options4(&mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
"program_name", "mysql");
if (!mysql_real_connect(&mysql, host, user, password,
database, opt_mysql_port, opt_mysql_unix_port,
connect_flag | CLIENT_MULTI_STATEMENTS))
......
......@@ -370,6 +370,9 @@ int main(int argc,char *argv[])
if (opt_default_auth && *opt_default_auth)
mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
mysql_options(&mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
mysql_options4(&mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
"program_name", "mysqladmin");
if (sql_connect(&mysql, option_wait))
{
/*
......
......@@ -1745,6 +1745,9 @@ static Exit_status safe_connect()
mysql_options(mysql, MYSQL_SHARED_MEMORY_BASE_NAME,
shared_memory_base_name);
#endif
mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
"program_name", "mysqlbinlog");
if (!mysql_real_connect(mysql, host, user, pass, 0, port, sock, 0))
{
error("Failed on connect: %s", mysql_error(mysql));
......
......@@ -915,6 +915,9 @@ static int dbConnect(char *host, char *user, char *passwd)
mysql_options(&mysql_connection, MYSQL_DEFAULT_AUTH, opt_default_auth);
mysql_options(&mysql_connection, MYSQL_SET_CHARSET_NAME, default_charset);
mysql_options(&mysql_connection, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
mysql_options4(&mysql_connection, MYSQL_OPT_CONNECT_ATTR_ADD,
"program_name", "mysqlcheck");
if (!(sock = mysql_real_connect(&mysql_connection, host, user, passwd,
NULL, opt_mysql_port, opt_mysql_unix_port, 0)))
{
......
......@@ -1542,6 +1542,9 @@ static int connect_to_db(char *host, char *user,char *passwd)
if (opt_default_auth && *opt_default_auth)
mysql_options(&mysql_connection, MYSQL_DEFAULT_AUTH, opt_default_auth);
mysql_options(&mysql_connection, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
mysql_options4(&mysql_connection, MYSQL_OPT_CONNECT_ATTR_ADD,
"program_name", "mysqldump");
mysql= &mysql_connection; /* So we can mysql_close() it properly */
if (!mysql_real_connect(&mysql_connection,host,user,passwd,
NULL,opt_mysql_port,opt_mysql_unix_port, 0))
......
......@@ -456,6 +456,9 @@ static MYSQL *db_connect(char *host, char *database,
mysql_options(mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset);
mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
"program_name", "mysqlimport");
if (!(mysql_real_connect(mysql,host,user,passwd,
database,opt_mysql_port,opt_mysql_unix_port,
0)))
......
......@@ -141,6 +141,9 @@ int main(int argc, char **argv)
if (opt_default_auth && *opt_default_auth)
mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
mysql_options(&mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
mysql_options4(&mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
"program_name", "mysqlshow");
if (!(mysql_real_connect(&mysql,host,user,opt_password,
(first_argument_uses_wildcards) ? "" :
argv[0],opt_mysql_port,opt_mysql_unix_port,
......
......@@ -362,6 +362,9 @@ int main(int argc, char **argv)
if (opt_default_auth && *opt_default_auth)
mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
mysql_options(&mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
mysql_options4(&mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
"program_name", "mysqlslap");
if (!opt_only_print)
{
if (!(mysql_real_connect(&mysql, host, user, opt_password,
......
......@@ -5648,6 +5648,10 @@ void safe_connect(MYSQL* mysql, const char *name, const char *host,
verbose_msg("Connecting to server %s:%d (socket %s) as '%s'"
", connection '%s', attempt %d ...",
host, port, sock, user, name, failed_attempts);
mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
"program_name", "mysqltest");
while(!mysql_real_connect(mysql, host,user, pass, db, port, sock,
CLIENT_MULTI_STATEMENTS | CLIENT_REMEMBER_OPTIONS))
{
......@@ -5748,7 +5752,9 @@ int connect_n_handle_errors(struct st_command *command,
replace_dynstr_append(ds, command->query);
dynstr_append_mem(ds, ";\n", 2);
}
mysql_options(con, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
mysql_options4(con, MYSQL_OPT_CONNECT_ATTR_ADD, "program_name", "mysqltest");
while (!mysql_real_connect(con, host, user, pass, db, port, sock ? sock: 0,
CLIENT_MULTI_STATEMENTS))
{
......
......@@ -557,6 +557,8 @@ int STDCALL mysql_list_processes_cont(MYSQL_RES **ret, MYSQL *mysql,
int status);
int STDCALL mysql_options(MYSQL *mysql,enum mysql_option option,
const void *arg);
int STDCALL mysql_options4(MYSQL *mysql,enum mysql_option option,
const void *arg1, const void *arg2);
void STDCALL mysql_free_result(MYSQL_RES *result);
int STDCALL mysql_free_result_start(MYSQL_RES *result);
int STDCALL mysql_free_result_cont(MYSQL_RES *result, int status);
......
......@@ -552,6 +552,8 @@ int mysql_list_processes_cont(MYSQL_RES **ret, MYSQL *mysql,
int status);
int mysql_options(MYSQL *mysql,enum mysql_option option,
const void *arg);
int mysql_options4(MYSQL *mysql,enum mysql_option option,
const void *arg1, const void *arg2);
void mysql_free_result(MYSQL_RES *result);
int mysql_free_result_start(MYSQL_RES *result);
int mysql_free_result_cont(MYSQL_RES *result, int status);
......
......@@ -1921,6 +1921,7 @@ typedef struct PSI_digest_locker* (*digest_add_token_v1_t)
typedef int (*set_thread_connect_attrs_v1_t)(const char *buffer, uint length,
const void *from_cs);
/**
Performance Schema Interface, version 1.
@since PSI_VERSION_1
......
......@@ -264,7 +264,8 @@ enum enum_server_command
CLIENT_SSL_VERIFY_SERVER_CERT | \
CLIENT_REMEMBER_OPTIONS | \
CLIENT_PROGRESS | \
CLIENT_PLUGIN_AUTH)
CLIENT_PLUGIN_AUTH | \
CLIENT_CONNECT_ATTRS)
/*
To be added later:
......
......@@ -43,6 +43,8 @@ struct st_mysql_options_extention {
const char *proc_info,
uint proc_info_length);
struct mysql_async_context *async_context;
HASH connection_attributes;
size_t connection_attributes_length;
};
typedef struct st_mysql_methods
......@@ -116,6 +118,7 @@ int mysql_client_plugin_init();
void mysql_client_plugin_deinit();
struct st_mysql_client_plugin;
extern struct st_mysql_client_plugin *mysql_client_builtins[];
uchar * send_client_connect_attrs(MYSQL *mysql, uchar *buf);
/* Non-blocking client API. */
void my_context_install_suspend_resume_hook(struct mysql_async_context *b,
......
......@@ -34,7 +34,8 @@ extern char * mysql_unix_port;
CLIENT_SECURE_CONNECTION | \
CLIENT_MULTI_RESULTS | \
CLIENT_PS_MULTI_RESULTS | \
CLIENT_PLUGIN_AUTH)
CLIENT_PLUGIN_AUTH | \
CLIENT_CONNECT_ATTRS)
sig_handler my_pipe_sig_handler(int sig);
void read_user_name(char *name);
......
......@@ -638,7 +638,6 @@ void init_embedded_mysql(MYSQL *mysql, int client_flag)
thd->mysql= mysql;
mysql->server_version= server_version;
mysql->client_flag= client_flag;
//mysql->server_capabilities= client_flag;
init_alloc_root(&mysql->field_alloc, 8192, 0, MYF(0));
}
......@@ -698,12 +697,38 @@ err:
}
static void
emb_transfer_connect_attrs(MYSQL *mysql)
{
#ifdef HAVE_PSI_THREAD_INTERFACE
if (mysql->options.extension &&
mysql->options.extension->connection_attributes_length)
{
uchar *buf, *ptr;
THD *thd= (THD*)mysql->thd;
size_t length= mysql->options.extension->connection_attributes_length;
/* 9 = max length of the serialized length */
ptr= buf= (uchar *) my_alloca(length + 9);
send_client_connect_attrs(mysql, buf);
net_field_length_ll(&ptr);
PSI_THREAD_CALL(set_thread_connect_attrs)((char *) ptr, length, thd->charset());
my_afree(buf);
}
#endif
}
#ifdef NO_EMBEDDED_ACCESS_CHECKS
int check_embedded_connection(MYSQL *mysql, const char *db)
{
int result;
LEX_STRING db_str = { (char*)db, db ? strlen(db) : 0 };
THD *thd= (THD*)mysql->thd;
/* the server does the same as the client */
mysql->server_capabilities= mysql->client_flag;
thd_init_client_charset(thd, mysql->charset->number);
thd->update_charset();
Security_context *sctx= thd->security_ctx;
......@@ -713,6 +738,7 @@ int check_embedded_connection(MYSQL *mysql, const char *db)
sctx->user= my_strdup(mysql->user, MYF(0));
sctx->proxy_user[0]= 0;
sctx->master_access= GLOBAL_ACLS; // Full rights
emb_transfer_connect_attrs(mysql);
/* Change database if necessary */
if (!(result= (db && db[0] && mysql_change_db(thd, &db_str, FALSE))))
my_ok(thd);
......@@ -728,11 +754,16 @@ int check_embedded_connection(MYSQL *mysql, const char *db)
we emulate a COM_CHANGE_USER user here,
it's easier than to emulate the complete 3-way handshake
*/
char buf[USERNAME_LENGTH + SCRAMBLE_LENGTH + 1 + 2*NAME_LEN + 2], *end;
char *buf, *end;
NET *net= &mysql->net;
THD *thd= (THD*)mysql->thd;
Security_context *sctx= thd->security_ctx;
size_t connect_attrs_len=
(mysql->options.extension) ?
mysql->options.extension->connection_attributes_length : 0;
buf= my_alloca(USERNAME_LENGTH + SCRAMBLE_LENGTH + 1 + 2*NAME_LEN + 2 +
connect_attrs_len + 2);
if (mysql->options.client_ip)
{
sctx->host= my_strdup(mysql->options.client_ip, MYF(0));
......@@ -766,6 +797,13 @@ int check_embedded_connection(MYSQL *mysql, const char *db)
int2store(end, (ushort) mysql->charset->number);
end+= 2;
end= strmake(end, "mysql_native_password", NAME_LEN) + 1;
/* the server does the same as the client */
mysql->server_capabilities= mysql->client_flag;
end= (char *) send_client_connect_attrs(mysql, (uchar *) end);
/* acl_authenticate() takes the data from thd->net->read_pos */
thd->net.read_pos= (uchar*)buf;
......@@ -774,6 +812,7 @@ int check_embedded_connection(MYSQL *mysql, const char *db)
my_free(thd->security_ctx->user);
goto err;
}
my_afree(buf);
return 0;
err:
......@@ -781,6 +820,7 @@ err:
memcpy(net->sqlstate,
mysql_errno_to_sqlstate(thd->get_stmt_da()->sql_errno()),
sizeof(net->sqlstate)-1);
my_afree(buf);
return 1;
}
#endif
......
# must return 0, 6
SELECT SUM(ISNULL(ATTR_VALUE)), COUNT(*)
FROM performance_schema.session_connect_attrs
WHERE ATTR_NAME IN ('_os', '_client_name', '_pid',
'_client_version', '_platform', 'program_name')
AND PROCESSLIST_ID = CONNECTION_ID();
SUM(ISNULL(ATTR_VALUE)) COUNT(*)
0 6
# must return 1
SELECT COUNT(DISTINCT PROCESSLIST_ID)
FROM performance_schema.session_connect_attrs;
COUNT(DISTINCT PROCESSLIST_ID)
1
# must return 0, 6
SELECT SUM(ISNULL(ATTR_VALUE)), COUNT(*)
FROM performance_schema.session_account_connect_attrs
WHERE ATTR_NAME IN ('_os', '_client_name', '_pid',
'_client_version', '_platform', 'program_name')
AND PROCESSLIST_ID = CONNECTION_ID();
SUM(ISNULL(ATTR_VALUE)) COUNT(*)
0 6
# must return 1
SELECT COUNT(DISTINCT PROCESSLIST_ID)
FROM performance_schema.session_account_connect_attrs;
COUNT(DISTINCT PROCESSLIST_ID)
1
CREATE USER wl5924@localhost;
# must return 1
SELECT COUNT(DISTINCT PROCESSLIST_ID)
FROM performance_schema.session_account_connect_attrs;
COUNT(DISTINCT PROCESSLIST_ID)
1
# must return 2
SELECT COUNT(DISTINCT PROCESSLIST_ID)
FROM performance_schema.session_connect_attrs;
COUNT(DISTINCT PROCESSLIST_ID)
2
SELECT COUNT(DISTINCT PROCESSLIST_ID)
FROM performance_schema.session_account_connect_attrs;
ERROR 42000: SELECT command denied to user 'wl5924'@'localhost' for table 'session_account_connect_attrs'
SELECT COUNT(DISTINCT PROCESSLIST_ID)
FROM performance_schema.session_connect_attrs;
ERROR 42000: SELECT command denied to user 'wl5924'@'localhost' for table 'session_connect_attrs'
grant select on performance_schema.* to wl5924@localhost;
SELECT SUM(ISNULL(ATTR_VALUE)), COUNT(*)
FROM performance_schema.session_account_connect_attrs
WHERE ATTR_NAME IN ('_os', '_client_name', '_pid',
'_client_version', '_platform', 'program_name')
AND PROCESSLIST_ID = CONNECTION_ID();
SUM(ISNULL(ATTR_VALUE)) COUNT(*)
0 6
DROP USER wl5924@localhost;
# Session connect attributes test
--source include/have_perfschema.inc
# although the connection attributes transfer code works
# with embedded P_S is not active, so the test won't run.
# TODO: remove this when P_S works with embedded.
--source include/not_embedded.inc
# make sure we're alone
let $count_sessions= 1;
--source include/wait_until_count_sessions.inc
# basic performance_schema.session_connect_attrs tests
# check the presense of the pre-defined attributes
--echo # must return 0, 6
SELECT SUM(ISNULL(ATTR_VALUE)), COUNT(*)
FROM performance_schema.session_connect_attrs
WHERE ATTR_NAME IN ('_os', '_client_name', '_pid',
'_client_version', '_platform', 'program_name')
AND PROCESSLIST_ID = CONNECTION_ID();
# check the presense of the pre-defined attributes
--echo # must return 1
SELECT COUNT(DISTINCT PROCESSLIST_ID)
FROM performance_schema.session_connect_attrs;
# basic performance_schema.session_account_connect_attrs tests
# check the presense of the pre-defined attributes
--echo # must return 0, 6
SELECT SUM(ISNULL(ATTR_VALUE)), COUNT(*)
FROM performance_schema.session_account_connect_attrs
WHERE ATTR_NAME IN ('_os', '_client_name', '_pid',
'_client_version', '_platform', 'program_name')
AND PROCESSLIST_ID = CONNECTION_ID();
# check the presense of the pre-defined attributes
--echo # must return 1
SELECT COUNT(DISTINCT PROCESSLIST_ID)
FROM performance_schema.session_account_connect_attrs;
CREATE USER wl5924@localhost;
connect(non_privileged_user,localhost,wl5924,,test);
connection default;
--echo # must return 1
SELECT COUNT(DISTINCT PROCESSLIST_ID)
FROM performance_schema.session_account_connect_attrs;
--echo # must return 2
SELECT COUNT(DISTINCT PROCESSLIST_ID)
FROM performance_schema.session_connect_attrs;
connection non_privileged_user;
--error ER_TABLEACCESS_DENIED_ERROR
SELECT COUNT(DISTINCT PROCESSLIST_ID)
FROM performance_schema.session_account_connect_attrs;
--error ER_TABLEACCESS_DENIED_ERROR
SELECT COUNT(DISTINCT PROCESSLIST_ID)
FROM performance_schema.session_connect_attrs;
connection default;
disconnect non_privileged_user;
grant select on performance_schema.* to wl5924@localhost;
change_user wl5924;
SELECT SUM(ISNULL(ATTR_VALUE)), COUNT(*)
FROM performance_schema.session_account_connect_attrs
WHERE ATTR_NAME IN ('_os', '_client_name', '_pid',
'_client_version', '_platform', 'program_name')
AND PROCESSLIST_ID = CONNECTION_ID();
change_user root,,test;
DROP USER wl5924@localhost;
# Wait till all disconnects are completed
--source include/wait_until_count_sessions.inc
This diff is collapsed.
......@@ -30,11 +30,11 @@
*/
#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | \
CLIENT_LONG_FLAG | \
CLIENT_SECURE_CONNECTION | \
CLIENT_TRANSACTIONS | \
CLIENT_PROTOCOL_41 | \
CLIENT_SECURE_CONNECTION | \
CLIENT_PLUGIN_AUTH)
CLIENT_PLUGIN_AUTH | \
CLIENT_CONNECT_ATTRS)
#define read_user_name(A) {}
#undef _CUSTOMCONFIG_
......
......@@ -8217,6 +8217,56 @@ static bool find_mpvio_user(MPVIO_EXT *mpvio)
mpvio->acl_user->plugin.str));
DBUG_RETURN(0);
}
static bool
read_client_connect_attrs(char **ptr, char *end,
const CHARSET_INFO *from_cs)
{
size_t length, length_length;
size_t max_bytes_available= end - *ptr;
/* not enough bytes to hold the length */
if ((*ptr) >= (end - 1))
return true;
/* read the length */
if (max_bytes_available >= 9)
{
char *ptr_save= *ptr;
length= net_field_length_ll((uchar **) ptr);
length_length= *ptr - ptr_save;
DBUG_ASSERT(length_length <= 9);
}
else
{
/* to avoid reading unallocated and uninitialized memory */
char buf[10]={'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0',},
*len_ptr= buf;
memcpy(buf, *ptr, max_bytes_available);
length= net_field_length_ll((uchar **) &len_ptr);
length_length= len_ptr - buf;
*ptr+= length_length;
if (max_bytes_available < length_length)
return true;
}
max_bytes_available-= length_length;
/* length says there're more data than can fit into the packet */
if (length > max_bytes_available)
return true;
/* impose an artificial length limit of 64k */
if (length > 65535)
return true;
#ifdef HAVE_PSI_THREAD_INTERFACE
if (PSI_THREAD_CALL(set_thread_connect_attrs)(*ptr, length, from_cs) &&
current_thd->variables.log_warnings)
sql_print_warning("Connection attributes of length %lu were truncated",
(unsigned long) length);
#endif
return false;
}
#endif
/* the packet format is described in send_change_user_packet() */
......@@ -8269,13 +8319,14 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
uint db_len= strlen(db);
char *ptr= db + db_len + 1;
char *next_field= db + db_len + 1;
if (ptr + 1 < end)
if (next_field + 1 < end)
{
if (thd_init_client_charset(thd, uint2korr(ptr)))
if (thd_init_client_charset(thd, uint2korr(next_field)))
DBUG_RETURN(1);
thd->update_charset();
next_field+= 2;
}
/* Convert database and user names to utf8 */
......@@ -8318,13 +8369,13 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
char *client_plugin;
if (thd->client_capabilities & CLIENT_PLUGIN_AUTH)
{
client_plugin= ptr + 2;
if (client_plugin >= end)
if (next_field >= end)
{
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
DBUG_RETURN(1);
}
client_plugin= fix_plugin_ptr(client_plugin);
client_plugin= fix_plugin_ptr(next_field);
next_field+= strlen(next_field) + 1;
}
else
{
......@@ -8344,6 +8395,11 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
}
}
if ((mpvio->thd->client_capabilities & CLIENT_CONNECT_ATTRS) &&
read_client_connect_attrs(&next_field, end,
mpvio->thd->charset()))
return packet_error;
DBUG_PRINT("info", ("client_plugin=%s, restart", client_plugin));
/*
Remember the data part of the packet, to present it to plugin in
......@@ -8482,7 +8538,8 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
/* strlen() can't be easily deleted without changing protocol */
db_len= db ? strlen(db) : 0;
char *client_plugin= passwd + passwd_len + (db ? db_len + 1 : 0);
char *next_field;
char *client_plugin= next_field= passwd + passwd_len + (db ? db_len + 1 : 0);
/* Since 4.1 all database names are stored in utf8 */
if (db)
......@@ -8549,6 +8606,7 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
(client_plugin < (char *)net->read_pos + pkt_len))
{
client_plugin= fix_plugin_ptr(client_plugin);
next_field+= strlen(next_field) + 1;
}
else
{
......@@ -8570,7 +8628,12 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
mpvio->acl_user->plugin= old_password_plugin_name;
}
}
if ((thd->client_capabilities & CLIENT_CONNECT_ATTRS) &&
read_client_connect_attrs(&next_field, ((char *)net->read_pos) + pkt_len,
mpvio->thd->charset()))
return packet_error;
/*
if the acl_user needs a different plugin to authenticate
(specified in GRANT ... AUTHENTICATED VIA plugin_name ..)
......
......@@ -54,6 +54,9 @@
#ifndef PFS_STATEMENTS_STACK_SIZE
#define PFS_STATEMENTS_STACK_SIZE 10
#endif
#ifndef PFS_CONNECT_ATTRS_SIZE
#define PFS_SESSION_CONNECT_ATTRS_SIZE 2048
#endif
struct PFS_sizing_hints
{
......
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