Skip to content

Commit 31a9208

Browse files
committed
Bug #12998841: libmysql divulges plaintext password upon request in 5.5
1. Clear text password client plugin disabled by default. 2. Added an environment variable LIBMYSQL_ENABLE_CLEARTEXT_PLUGIN, that when set to something starting with '1', 'Y' or 'y' will enable the clear text plugin for all connections. 3. Added a new mysql_options() option : MYSQL_ENABLE_CLEARTEXT_PLUGIN that takes an my_bool argument. When the value of the argument is non-zero the clear text plugin is enabled for this connection only. 4. Added an enable-cleartext-plugin config file option that takes a numeric argument. If the numeric value of the numeric argument is non-zero the clear text plugin is enabled for the connection 5. Added a boolean command line option "--enable_cleartext_plugin" to mysql, mysqlslap and mysqladmin. When specified it will call mysql_options with the effect of alibaba#3 6. Added a new CLEARTEXT option to the connect command in mysqltest. When specified it will enable the cleartext plugin for usage. 7. Added test cases and updated existing ones that need the clear text plugin.
1 parent e6f0b97 commit 31a9208

11 files changed

Lines changed: 119 additions & 14 deletions

File tree

client/client_priv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ enum options_client
8787
OPT_PLUGIN_DIR,
8888
OPT_DEFAULT_AUTH,
8989
OPT_DEFAULT_PLUGIN,
90+
OPT_ENABLE_CLEARTEXT_PLUGIN,
9091
OPT_MAX_CLIENT_OPTION
9192
};
9293

client/mysql.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ static my_bool column_types_flag;
148148
static my_bool preserve_comments= 0;
149149
static ulong opt_max_allowed_packet, opt_net_buffer_length;
150150
static uint verbose=0,opt_silent=0,opt_mysql_port=0, opt_local_infile=0;
151+
static uint opt_enable_cleartext_plugin= 0;
152+
static my_bool using_opt_enable_cleartext_plugin= 0;
151153
static uint my_end_arg;
152154
static char * opt_mysql_unix_port=0;
153155
static int connect_flag=CLIENT_INTERACTIVE;
@@ -1409,6 +1411,10 @@ static struct my_option my_long_options[] =
14091411
&default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
14101412
{"delimiter", OPT_DELIMITER, "Delimiter to be used.", &delimiter_str,
14111413
&delimiter_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1414+
{"enable_cleartext_plugin", OPT_ENABLE_CLEARTEXT_PLUGIN,
1415+
"Enable/disable the clear text authentication plugin.",
1416+
&opt_enable_cleartext_plugin, &opt_enable_cleartext_plugin,
1417+
0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
14121418
{"execute", 'e', "Execute command and quit. (Disables --force and history file.)", 0,
14131419
0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
14141420
{"vertical", 'E', "Print the output of a query (rows) vertically.",
@@ -1636,6 +1642,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
16361642
case OPT_LOCAL_INFILE:
16371643
using_opt_local_infile=1;
16381644
break;
1645+
case OPT_ENABLE_CLEARTEXT_PLUGIN:
1646+
using_opt_enable_cleartext_plugin= TRUE;
1647+
break;
16391648
case OPT_TEE:
16401649
if (argument == disabled_my_option)
16411650
{
@@ -4321,6 +4330,10 @@ sql_real_connect(char *host,char *database,char *user,char *password,
43214330
if (opt_default_auth && *opt_default_auth)
43224331
mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
43234332

4333+
if (using_opt_enable_cleartext_plugin)
4334+
mysql_options(&mysql, MYSQL_ENABLE_CLEARTEXT_PLUGIN,
4335+
(char*) &opt_enable_cleartext_plugin);
4336+
43244337
if (!mysql_real_connect(&mysql, host, user, password,
43254338
database, opt_mysql_port, opt_mysql_unix_port,
43264339
connect_flag | CLIENT_MULTI_STATEMENTS))

client/mysqladmin.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ static uint opt_count_iterations= 0, my_end_arg;
4343
static ulong opt_connect_timeout, opt_shutdown_timeout;
4444
static char * unix_port=0;
4545
static char *opt_plugin_dir= 0, *opt_default_auth= 0;
46+
static uint opt_enable_cleartext_plugin= 0;
47+
static my_bool using_opt_enable_cleartext_plugin= 0;
4648

4749
#ifdef HAVE_SMEM
4850
static char *shared_memory_base_name=0;
@@ -212,6 +214,10 @@ static struct my_option my_long_options[] =
212214
"Default authentication client-side plugin to use.",
213215
&opt_default_auth, &opt_default_auth, 0,
214216
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
217+
{"enable_cleartext_plugin", OPT_ENABLE_CLEARTEXT_PLUGIN,
218+
"Enable/disable the clear text authentication plugin.",
219+
&opt_enable_cleartext_plugin, &opt_enable_cleartext_plugin,
220+
0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
215221
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
216222
};
217223

@@ -282,6 +288,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
282288
opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
283289
opt->name);
284290
break;
291+
case OPT_ENABLE_CLEARTEXT_PLUGIN:
292+
using_opt_enable_cleartext_plugin= TRUE;
293+
break;
285294
}
286295
if (error)
287296
{
@@ -354,6 +363,10 @@ int main(int argc,char *argv[])
354363
if (opt_default_auth && *opt_default_auth)
355364
mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
356365

366+
if (using_opt_enable_cleartext_plugin)
367+
mysql_options(&mysql, MYSQL_ENABLE_CLEARTEXT_PLUGIN,
368+
(char*) &opt_enable_cleartext_plugin);
369+
357370
if (sql_connect(&mysql, option_wait))
358371
{
359372
/*

client/mysqlslap.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ static char *host= NULL, *opt_password= NULL, *user= NULL,
125125
*post_system= NULL,
126126
*opt_mysql_unix_port= NULL;
127127
static char *opt_plugin_dir= 0, *opt_default_auth= 0;
128+
static uint opt_enable_cleartext_plugin= 0;
129+
static my_bool using_opt_enable_cleartext_plugin= 0;
128130

129131
const char *delimiter= "\n";
130132

@@ -348,6 +350,9 @@ int main(int argc, char **argv)
348350
if (opt_default_auth && *opt_default_auth)
349351
mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
350352

353+
if (using_opt_enable_cleartext_plugin)
354+
mysql_options(&mysql, MYSQL_ENABLE_CLEARTEXT_PLUGIN,
355+
(char*) &opt_enable_cleartext_plugin);
351356
if (!opt_only_print)
352357
{
353358
if (!(mysql_real_connect(&mysql, host, user, opt_password,
@@ -603,6 +608,10 @@ static struct my_option my_long_options[] =
603608
"Detach (close and reopen) connections after X number of requests.",
604609
&detach_rate, &detach_rate, 0, GET_UINT, REQUIRED_ARG,
605610
0, 0, 0, 0, 0, 0},
611+
{"enable_cleartext_plugin", OPT_ENABLE_CLEARTEXT_PLUGIN,
612+
"Enable/disable the clear text authentication plugin.",
613+
&opt_enable_cleartext_plugin, &opt_enable_cleartext_plugin,
614+
0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
606615
{"engine", 'e', "Storage engine to use for creating the table.",
607616
&default_engine, &default_engine, 0,
608617
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
@@ -761,6 +770,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
761770
case 'I': /* Info */
762771
usage();
763772
exit(0);
773+
case OPT_ENABLE_CLEARTEXT_PLUGIN:
774+
using_opt_enable_cleartext_plugin= TRUE;
775+
break;
764776
}
765777
DBUG_RETURN(0);
766778
}

client/mysqltest.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5456,7 +5456,7 @@ void do_connect(struct st_command *command)
54565456
int con_port= opt_port;
54575457
char *con_options;
54585458
my_bool con_ssl= 0, con_compress= 0;
5459-
my_bool con_pipe= 0, con_shm= 0;
5459+
my_bool con_pipe= 0, con_shm= 0, con_cleartext_enable= 0;
54605460
struct st_connection* con_slot;
54615461

54625462
static DYNAMIC_STRING ds_connection_name;
@@ -5546,6 +5546,8 @@ void do_connect(struct st_command *command)
55465546
con_pipe= 1;
55475547
else if (!strncmp(con_options, "SHM", 3))
55485548
con_shm= 1;
5549+
else if (!strncmp(con_options, "CLEARTEXT", 9))
5550+
con_cleartext_enable= 1;
55495551
else
55505552
die("Illegal option to connect: %.*s",
55515553
(int) (end - con_options), con_options);
@@ -5642,6 +5644,10 @@ void do_connect(struct st_command *command)
56425644
if (ds_default_auth.length)
56435645
mysql_options(&con_slot->mysql, MYSQL_DEFAULT_AUTH, ds_default_auth.str);
56445646

5647+
5648+
if (con_cleartext_enable)
5649+
mysql_options(&con_slot->mysql, MYSQL_ENABLE_CLEARTEXT_PLUGIN,
5650+
(char*) &con_cleartext_enable);
56455651
/* Special database to allow one to connect without a database name */
56465652
if (ds_database.length && !strcmp(ds_database.str,"*NO-ONE*"))
56475653
dynstr_set(&ds_database, "");

include/mysql.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ enum mysql_option
166166
MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION,
167167
MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH,
168168
MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT,
169-
MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH
169+
MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH,
170+
MYSQL_ENABLE_CLEARTEXT_PLUGIN
170171
};
171172

172173
/**

include/mysql.h.pp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,8 @@
262262
MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION,
263263
MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH,
264264
MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT,
265-
MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH
265+
MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH,
266+
MYSQL_ENABLE_CLEARTEXT_PLUGIN
266267
};
267268
struct st_mysql_options_extention;
268269
struct st_mysql_options {

include/sql_common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ extern const char *not_error_sqlstate;
3131
struct st_mysql_options_extention {
3232
char *plugin_dir;
3333
char *default_auth;
34+
my_bool enable_cleartext_plugin;
3435
};
3536

3637
typedef struct st_mysql_methods
@@ -104,6 +105,7 @@ int mysql_client_plugin_init();
104105
void mysql_client_plugin_deinit();
105106
struct st_mysql_client_plugin;
106107
extern struct st_mysql_client_plugin *mysql_client_builtins[];
108+
extern my_bool libmysql_cleartext_plugin_enabled;
107109

108110
#ifdef __cplusplus
109111
}

mysql-test/t/plugin_auth.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -422,10 +422,10 @@ CREATE USER uplain@localhost IDENTIFIED WITH 'cleartext_plugin_server'
422422
--echo ## test plugin auth
423423
--disable_query_log
424424
--error ER_ACCESS_DENIED_ERROR : this should fail : no grant
425-
connect(cleartext_fail_con,localhost,uplain,cleartext_test2);
425+
connect(cleartext_fail_con,localhost,uplain,cleartext_test2,,,,CLEARTEXT);
426426
--enable_query_log
427427

428-
connect(cleartext_con,localhost,uplain,cleartext_test);
428+
connect(cleartext_con,localhost,uplain,cleartext_test,,,,CLEARTEXT);
429429
connection cleartext_con;
430430
select USER(),CURRENT_USER();
431431

sql-common/client.c

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,7 +1136,8 @@ static const char *default_options[]=
11361136
"connect-timeout", "local-infile", "disable-local-infile",
11371137
"ssl-cipher", "max-allowed-packet", "protocol", "shared-memory-base-name",
11381138
"multi-results", "multi-statements", "multi-queries", "secure-auth",
1139-
"report-data-truncation", "plugin-dir", "default-auth",
1139+
"report-data-truncation", "plugin-dir", "default-auth",
1140+
"enable-cleartext-plugin",
11401141
NullS
11411142
};
11421143
enum option_id {
@@ -1148,6 +1149,7 @@ enum option_id {
11481149
OPT_ssl_cipher, OPT_max_allowed_packet, OPT_protocol, OPT_shared_memory_base_name,
11491150
OPT_multi_results, OPT_multi_statements, OPT_multi_queries, OPT_secure_auth,
11501151
OPT_report_data_truncation, OPT_plugin_dir, OPT_default_auth,
1152+
OPT_enable_cleartext_plugin,
11511153
OPT_keep_this_one_last
11521154
};
11531155

@@ -1180,14 +1182,27 @@ static int add_init_command(struct st_mysql_options *options, const char *cmd)
11801182
return 0;
11811183
}
11821184

1183-
#define EXTENSION_SET_STRING(OPTS, X, STR) \
1184-
if ((OPTS)->extension) \
1185-
my_free((OPTS)->extension->X); \
1186-
else \
1185+
#define ALLOCATE_EXTENSIONS(OPTS) \
11871186
(OPTS)->extension= (struct st_mysql_options_extention *) \
11881187
my_malloc(sizeof(struct st_mysql_options_extention), \
1189-
MYF(MY_WME | MY_ZEROFILL)); \
1190-
(OPTS)->extension->X= my_strdup((STR), MYF(MY_WME));
1188+
MYF(MY_WME | MY_ZEROFILL)) \
1189+
1190+
#define ENSURE_EXTENSIONS_PRESENT(OPTS) \
1191+
do { \
1192+
if (!(OPTS)->extension) \
1193+
ALLOCATE_EXTENSIONS(OPTS); \
1194+
} while (0)
1195+
1196+
1197+
#define EXTENSION_SET_STRING(OPTS, X, STR) \
1198+
do { \
1199+
if ((OPTS)->extension) \
1200+
my_free((OPTS)->extension->X); \
1201+
else \
1202+
ALLOCATE_EXTENSIONS(OPTS); \
1203+
(OPTS)->extension->X= ((STR) != NULL) ? \
1204+
my_strdup((STR), MYF(MY_WME)) : NULL; \
1205+
} while (0)
11911206

11921207
void mysql_read_default_options(struct st_mysql_options *options,
11931208
const char *filename,const char *group)
@@ -1386,6 +1401,12 @@ void mysql_read_default_options(struct st_mysql_options *options,
13861401
case OPT_default_auth:
13871402
EXTENSION_SET_STRING(options, default_auth, opt_arg);
13881403
break;
1404+
1405+
case OPT_enable_cleartext_plugin:
1406+
ENSURE_EXTENSIONS_PRESENT(options);
1407+
options->extension->enable_cleartext_plugin=
1408+
(!opt_arg || atoi(opt_arg) != 0) ? TRUE : FALSE;
1409+
13891410
default:
13901411
DBUG_PRINT("warning",("unknown option: %s",option[0]));
13911412
}
@@ -2782,6 +2803,27 @@ static void client_mpvio_info(MYSQL_PLUGIN_VIO *vio,
27822803
mpvio_info(mpvio->mysql->net.vio, info);
27832804
}
27842805

2806+
2807+
my_bool libmysql_cleartext_plugin_enabled= 0;
2808+
2809+
static my_bool check_plugin_enabled(MYSQL *mysql, auth_plugin_t *plugin)
2810+
{
2811+
if (plugin == &clear_password_client_plugin &&
2812+
(!libmysql_cleartext_plugin_enabled &&
2813+
(!mysql->options.extension ||
2814+
!mysql->options.extension->enable_cleartext_plugin)))
2815+
{
2816+
set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD,
2817+
unknown_sqlstate,
2818+
ER(CR_AUTH_PLUGIN_CANNOT_LOAD),
2819+
clear_password_client_plugin.name,
2820+
"plugin not enabled");
2821+
return TRUE;
2822+
}
2823+
return FALSE;
2824+
}
2825+
2826+
27852827
/**
27862828
Client side of the plugin driver authentication.
27872829
@@ -2824,6 +2866,9 @@ int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
28242866
auth_plugin_name= auth_plugin->name;
28252867
}
28262868

2869+
if (check_plugin_enabled(mysql, auth_plugin))
2870+
DBUG_RETURN(1);
2871+
28272872
DBUG_PRINT ("info", ("using plugin %s", auth_plugin_name));
28282873

28292874
mysql->net.last_errno= 0; /* just in case */
@@ -2915,6 +2960,9 @@ int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
29152960
auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN)))
29162961
DBUG_RETURN (1);
29172962

2963+
if (check_plugin_enabled(mysql, auth_plugin))
2964+
DBUG_RETURN(1);
2965+
29182966
mpvio.plugin= auth_plugin;
29192967
res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql);
29202968

@@ -4117,6 +4165,11 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg)
41174165
case MYSQL_DEFAULT_AUTH:
41184166
EXTENSION_SET_STRING(&mysql->options, default_auth, arg);
41194167
break;
4168+
case MYSQL_ENABLE_CLEARTEXT_PLUGIN:
4169+
ENSURE_EXTENSIONS_PRESENT(&mysql->options);
4170+
mysql->options.extension->enable_cleartext_plugin=
4171+
(*(my_bool*) arg) ? TRUE : FALSE;
4172+
break;
41204173
default:
41214174
DBUG_RETURN(1);
41224175
}
@@ -4336,5 +4389,3 @@ static int clear_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
43364389

43374390
return res ? CR_ERROR : CR_OK;
43384391
}
4339-
4340-

0 commit comments

Comments
 (0)