1502 lines
38 KiB
C++
1502 lines
38 KiB
C++
/*
|
|
Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
/**
|
|
@file
|
|
|
|
@brief
|
|
MySQL Configuration Utility
|
|
*/
|
|
|
|
/* ORACLE_WELCOME_COPYRIGHT_NOTICE */
|
|
#include "my_config.h"
|
|
#include <welcome_copyright_notice.h>
|
|
#include <signal.h>
|
|
#include <my_dir.h>
|
|
#include <my_rnd.h>
|
|
#include "my_aes.h"
|
|
#include "client_priv.h"
|
|
#include "my_default.h"
|
|
#include "my_default_priv.h"
|
|
|
|
#define MYSQL_CONFIG_EDITOR_VERSION "1.0"
|
|
#define MY_LINE_MAX 4096
|
|
#define MAX_COMMAND_LIMIT 100
|
|
/*
|
|
Header length for the login file.
|
|
4-byte (unused) + LOGIN_KEY_LEN
|
|
*/
|
|
#define MY_LOGIN_HEADER_LEN (4 + LOGIN_KEY_LEN)
|
|
|
|
static int g_fd;
|
|
|
|
/*
|
|
Length of the contents in login file
|
|
excluding the header part.
|
|
*/
|
|
static size_t file_size;
|
|
static const char *opt_user= NULL, *opt_password= NULL, *opt_host=NULL,
|
|
*opt_login_path= "client", *opt_socket= NULL, *opt_port= NULL;
|
|
|
|
static char my_login_file[FN_REFLEN];
|
|
static char my_key[LOGIN_KEY_LEN];
|
|
|
|
static my_bool opt_verbose, opt_all, tty_password= 0, opt_warn,
|
|
opt_remove_host, opt_remove_pass, opt_remove_user,
|
|
opt_remove_socket, opt_remove_port, login_path_specified= FALSE;
|
|
|
|
static int execute_commands(int command);
|
|
static int set_command(void);
|
|
static int remove_command(void);
|
|
static int print_command(void);
|
|
static void print_login_path(DYNAMIC_STRING *file_buf, const char *path_name);
|
|
static void remove_login_path(DYNAMIC_STRING *file_buf, const char *path_name);
|
|
static char* locate_login_path(DYNAMIC_STRING *file_buf, const char *path_name);
|
|
static my_bool check_and_create_login_file(void);
|
|
static void mask_password_and_print(char *buf);
|
|
static int reset_login_file(bool gen_key);
|
|
|
|
static int encrypt_buffer(const char *plain, int plain_len, char cipher[], const int aes_len);
|
|
static int decrypt_buffer(const char *cipher, int cipher_len, char plain[]);
|
|
static int encrypt_and_write_file(DYNAMIC_STRING *file_buf);
|
|
static int read_and_decrypt_file(DYNAMIC_STRING *file_buf);
|
|
static int do_handle_options(int argc, char *argv[]);
|
|
static void remove_options(DYNAMIC_STRING *file_buf, const char *path_name);
|
|
static void remove_option(DYNAMIC_STRING *file_buf, const char *path_name,
|
|
const char* option_name);
|
|
void generate_login_key(void);
|
|
static int read_login_key(void);
|
|
static int add_header(void);
|
|
static void my_perror(const char *msg);
|
|
|
|
static void verbose_msg(const char *fmt, ...);
|
|
static void print_version(void);
|
|
static void usage_program(void);
|
|
static void usage_command(int command);
|
|
extern "C" my_bool get_one_option(int optid, const struct my_option *opt,
|
|
char *argument);
|
|
|
|
enum commands {
|
|
MY_CONFIG_SET,
|
|
MY_CONFIG_REMOVE,
|
|
MY_CONFIG_PRINT,
|
|
MY_CONFIG_RESET,
|
|
MY_CONFIG_HELP
|
|
};
|
|
|
|
struct my_command_data {
|
|
const int id;
|
|
const char *name;
|
|
const char *description;
|
|
my_option *options;
|
|
my_bool (*get_one_option_func)(int optid,
|
|
const struct my_option *opt,
|
|
char *argument);
|
|
};
|
|
|
|
|
|
/* mysql_config_editor utility options. */
|
|
static struct my_option my_program_long_options[]=
|
|
{
|
|
#ifdef DBUG_OFF
|
|
{"debug", '#', "This is a non-debug version. Catch this and exit.",
|
|
0, 0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
|
|
#else
|
|
{"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
|
|
0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
|
|
#endif
|
|
{"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG,
|
|
NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"verbose", 'v', "Write more information.", &opt_verbose,
|
|
&opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
|
|
NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
|
|
};
|
|
|
|
/* Command-specific options. */
|
|
|
|
/* SET command options. */
|
|
static struct my_option my_set_command_options[]=
|
|
{
|
|
{"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG,
|
|
NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"host", 'h', "Host name to be entered into the login file.", &opt_host,
|
|
&opt_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"login-path", 'G', "Name of the login path to use in the login file. "
|
|
"(Default : client)", &opt_login_path, &opt_login_path, 0, GET_STR,
|
|
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"password", 'p', "Prompt for password to be entered into the login file.",
|
|
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"user", 'u', "User name to be entered into the login file.", &opt_user,
|
|
&opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"socket", 'S', "Socket path to be entered into login file.", &opt_socket,
|
|
&opt_socket, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"port", 'P', "Port number to be entered into login file.", &opt_port,
|
|
&opt_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"warn", 'w', "Warn and ask for confirmation if set command attempts to "
|
|
"overwrite an existing login path (enabled by default).",
|
|
&opt_warn, &opt_warn, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
|
|
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
|
|
};
|
|
|
|
/* REMOVE command options. */
|
|
static struct my_option my_remove_command_options[]=
|
|
{
|
|
{"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG,
|
|
NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"host", 'h', "Remove host name from the login path.",
|
|
&opt_remove_host, &opt_remove_host, 0, GET_BOOL, NO_ARG, 0, 0, 0,
|
|
0, 0, 0},
|
|
{"login-path", 'G', "Name of the login path from which options to "
|
|
"be removed (entire path would be removed if none of user, password, "
|
|
"host, socket, or port options are specified). (Default : client)",
|
|
&opt_login_path, &opt_login_path, 0, GET_STR, REQUIRED_ARG,
|
|
0, 0, 0, 0, 0, 0},
|
|
{"password", 'p', "Remove password from the login path.",
|
|
&opt_remove_pass, &opt_remove_pass, 0, GET_BOOL, NO_ARG, 0, 0, 0,
|
|
0, 0, 0},
|
|
{"user", 'u', "Remove user name from the login path.", &opt_remove_user,
|
|
&opt_remove_user, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"warn", 'w', "Warn and ask for confirmation if remove command attempts "
|
|
"to remove the default login path (client) if no login path is specified "
|
|
"(enabled by default).", &opt_warn, &opt_warn, 0, GET_BOOL, NO_ARG, 1,
|
|
0, 0, 0, 0, 0},
|
|
{"socket", 'S', "Remove socket path from the login path.", &opt_remove_socket,
|
|
&opt_remove_socket, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"port", 'P', "Remove port number from the login path.", &opt_remove_port,
|
|
&opt_remove_port, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
|
|
};
|
|
|
|
/* PRINT command options. */
|
|
static struct my_option my_print_command_options[]=
|
|
{
|
|
{"all", OPT_CONFIG_ALL, "Used with print command to print all login paths.",
|
|
&opt_all, &opt_all, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG,
|
|
NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"login-path", 'G', "Name of the login path to use in the login file. "
|
|
"(Default : client)", &opt_login_path, &opt_login_path, 0, GET_STR,
|
|
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
|
|
};
|
|
|
|
/* RESET command options. */
|
|
static struct my_option my_reset_command_options[]=
|
|
{
|
|
{"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG,
|
|
NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
|
|
};
|
|
|
|
/* HELP command options. */
|
|
static struct my_option my_help_command_options[]=
|
|
{
|
|
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
|
|
};
|
|
|
|
my_bool
|
|
my_program_get_one_option(int optid,
|
|
const struct my_option *opt MY_ATTRIBUTE((unused)),
|
|
char *argument)
|
|
{
|
|
switch(optid) {
|
|
case '#':
|
|
DBUG_PUSH(argument ? argument : "d:t:o,/tmp/mysql_config_editor.trace");
|
|
break;
|
|
case 'V':
|
|
print_version();
|
|
exit(0);
|
|
break;
|
|
case '?':
|
|
usage_program();
|
|
exit(0);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
my_bool
|
|
my_set_command_get_one_option(int optid,
|
|
const struct my_option *opt MY_ATTRIBUTE((unused)),
|
|
char *argument)
|
|
{
|
|
switch(optid) {
|
|
case 'p':
|
|
tty_password= 1;
|
|
break;
|
|
case 'G':
|
|
if (login_path_specified)
|
|
{
|
|
/* Error, we do not support multiple login paths. */
|
|
my_perror("Error: Use of multiple login paths is not supported. "
|
|
"Exiting..");
|
|
return 1;
|
|
}
|
|
login_path_specified= TRUE;
|
|
break;
|
|
case '?':
|
|
usage_command(MY_CONFIG_SET);
|
|
exit(0);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
my_bool
|
|
my_remove_command_get_one_option(int optid,
|
|
const struct my_option *opt MY_ATTRIBUTE((unused)),
|
|
char *argument)
|
|
{
|
|
switch(optid) {
|
|
case 'G':
|
|
if (login_path_specified)
|
|
{
|
|
/* Error, we do not support multiple login paths. */
|
|
my_perror("Error: Use of multiple login paths is not supported. "
|
|
"Exiting..");
|
|
return 1;
|
|
}
|
|
login_path_specified= TRUE;
|
|
break;
|
|
case '?':
|
|
usage_command(MY_CONFIG_REMOVE);
|
|
exit(0);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
my_bool
|
|
my_print_command_get_one_option(int optid,
|
|
const struct my_option *opt MY_ATTRIBUTE((unused)),
|
|
char *argument)
|
|
{
|
|
switch(optid) {
|
|
case 'G':
|
|
if (login_path_specified)
|
|
{
|
|
/* Error, we do not support multiple login paths. */
|
|
my_perror("Error: Use of multiple login paths is not supported. "
|
|
"Exiting..");
|
|
return 1;
|
|
}
|
|
login_path_specified= TRUE;
|
|
break;
|
|
case '?':
|
|
usage_command(MY_CONFIG_PRINT);
|
|
exit(0);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
my_bool
|
|
my_reset_command_get_one_option(int optid,
|
|
const struct my_option *opt MY_ATTRIBUTE((unused)),
|
|
char *argument)
|
|
{
|
|
switch(optid) {
|
|
case '?':
|
|
usage_command(MY_CONFIG_RESET);
|
|
exit(0);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static struct my_command_data command_data[]=
|
|
{
|
|
{
|
|
MY_CONFIG_SET,
|
|
"set",
|
|
"Write a login path to the login file.",
|
|
my_set_command_options,
|
|
my_set_command_get_one_option
|
|
},
|
|
{
|
|
MY_CONFIG_REMOVE,
|
|
"remove",
|
|
"Remove a login path from the login file.",
|
|
my_remove_command_options,
|
|
my_remove_command_get_one_option
|
|
},
|
|
{
|
|
MY_CONFIG_PRINT,
|
|
"print",
|
|
"Print the contents of login file in unencrypted form.",
|
|
my_print_command_options,
|
|
my_print_command_get_one_option
|
|
},
|
|
{
|
|
MY_CONFIG_RESET,
|
|
"reset",
|
|
"Empty the contents of the login file. The file is created\n"
|
|
"if it does not exist.",
|
|
my_reset_command_options,
|
|
my_reset_command_get_one_option
|
|
},
|
|
{
|
|
MY_CONFIG_HELP,
|
|
"help",
|
|
"Display a help message and exit.",
|
|
my_help_command_options,
|
|
NULL
|
|
},
|
|
{
|
|
0, NULL, NULL, NULL, NULL
|
|
}
|
|
};
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
MY_INIT(argv[0]);
|
|
DBUG_ENTER("main");
|
|
int command, rc= 0;
|
|
|
|
command= do_handle_options(argc, argv);
|
|
|
|
if (command > -1)
|
|
rc= execute_commands(command);
|
|
|
|
if (rc != 0)
|
|
{
|
|
my_perror("operation failed.");
|
|
DBUG_RETURN(1);
|
|
}
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
/**
|
|
Handle all the command line arguments.
|
|
|
|
program_name [program options] [command [command options]]
|
|
|
|
*/
|
|
static int do_handle_options(int argc, char *argv[])
|
|
{
|
|
DBUG_ENTER("do_handle_options");
|
|
|
|
const char *command_list[MAX_COMMAND_LIMIT + 1];
|
|
char **saved_argv= argv;
|
|
char **argv_cmd;
|
|
char *ptr; /* for free. */
|
|
int argc_cmd;
|
|
int rc, i, command= -1;
|
|
|
|
if (argc < 2)
|
|
{
|
|
usage_program();
|
|
exit(1);
|
|
}
|
|
|
|
if (!(ptr= (char *) my_malloc(PSI_NOT_INSTRUMENTED,
|
|
(argc + 2) * sizeof(char *),
|
|
MYF(MY_WME))))
|
|
goto error;
|
|
|
|
/* Handle program options. */
|
|
|
|
/* Prepare a list of supported commands to be used by my_handle_options(). */
|
|
for (i= 0; (command_data[i].name != NULL) && (i < MAX_COMMAND_LIMIT); i++)
|
|
command_list[i]= (char *) command_data[i].name;
|
|
command_list[i]= NULL;
|
|
|
|
if ((rc= my_handle_options(&argc, &argv, my_program_long_options,
|
|
my_program_get_one_option, command_list, FALSE)))
|
|
exit(rc);
|
|
|
|
if (argc == 0) /* No command specified. */
|
|
goto done;
|
|
|
|
for (i= 0; command_data[i].name != NULL; i++)
|
|
{
|
|
if (!strcmp(command_data[i].name, argv[0]))
|
|
{
|
|
command= i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (command == -1)
|
|
goto error;
|
|
|
|
/* Handle command options. */
|
|
|
|
argv_cmd= (char **)ptr;
|
|
argc_cmd= argc + 1;
|
|
|
|
/* Prepare a command line (argv) using the rest of the options. */
|
|
argv_cmd[0]= saved_argv[0];
|
|
memcpy((uchar *) (argv_cmd + 1), (uchar *) (argv),
|
|
(argc * sizeof(char *)));
|
|
argv_cmd[argc_cmd]= 0;
|
|
|
|
if ((rc= handle_options(&argc_cmd, &argv_cmd,
|
|
command_data[command].options,
|
|
command_data[command].get_one_option_func)))
|
|
exit(rc);
|
|
|
|
/* Do not allow multiple commands. */
|
|
if ( argc_cmd > 1)
|
|
goto error;
|
|
|
|
done:
|
|
my_free(ptr);
|
|
DBUG_RETURN(command);
|
|
|
|
error:
|
|
my_free(ptr);
|
|
usage_program();
|
|
exit(1);
|
|
}
|
|
|
|
|
|
static int execute_commands(int command)
|
|
{
|
|
DBUG_ENTER("execute_commands");
|
|
int rc= 0;
|
|
|
|
if ((rc= check_and_create_login_file()))
|
|
goto done;
|
|
|
|
switch(command_data[command].id) {
|
|
case MY_CONFIG_SET :
|
|
verbose_msg("Executing set command.\n");
|
|
rc= set_command();
|
|
break;
|
|
|
|
case MY_CONFIG_REMOVE :
|
|
verbose_msg("Executing remove command.\n");
|
|
rc= remove_command();
|
|
break;
|
|
|
|
case MY_CONFIG_PRINT :
|
|
verbose_msg("Executing print command.\n");
|
|
rc= print_command();
|
|
break;
|
|
|
|
case MY_CONFIG_RESET :
|
|
verbose_msg("Resetting login file.\n");
|
|
rc= reset_login_file(1);
|
|
break;
|
|
|
|
case MY_CONFIG_HELP :
|
|
verbose_msg("Printing usage info.\n");
|
|
usage_program();
|
|
break;
|
|
|
|
default :
|
|
my_perror("unknown command.");
|
|
exit(1);
|
|
}
|
|
|
|
done:
|
|
my_close(g_fd, MYF(MY_WME));
|
|
|
|
DBUG_RETURN(rc);
|
|
}
|
|
|
|
|
|
/**
|
|
Execute 'set' command.
|
|
|
|
@param void
|
|
|
|
@return -1 Error
|
|
0 Success
|
|
*/
|
|
|
|
static int set_command(void)
|
|
{
|
|
DBUG_ENTER("set_command");
|
|
|
|
DYNAMIC_STRING file_buf, path_buf;
|
|
|
|
init_dynamic_string(&path_buf, "", MY_LINE_MAX, MY_LINE_MAX);
|
|
init_dynamic_string(&file_buf, "", file_size, 3 * MY_LINE_MAX);
|
|
|
|
if (tty_password)
|
|
opt_password= get_tty_password(NullS);
|
|
|
|
if (file_size)
|
|
{
|
|
if (read_and_decrypt_file(&file_buf) == -1)
|
|
goto error;
|
|
}
|
|
|
|
dynstr_append(&path_buf, "["); /* --login=path */
|
|
if (opt_login_path)
|
|
dynstr_append(&path_buf, opt_login_path);
|
|
else
|
|
dynstr_append(&path_buf, "client");
|
|
dynstr_append(&path_buf, "]");
|
|
|
|
if (opt_user) /* --user */
|
|
{
|
|
dynstr_append(&path_buf, "\nuser = ");
|
|
dynstr_append(&path_buf, opt_user);
|
|
}
|
|
|
|
if (opt_password) /* --password */
|
|
{
|
|
dynstr_append(&path_buf, "\npassword = ");
|
|
dynstr_append(&path_buf, opt_password);
|
|
}
|
|
|
|
if (opt_host) /* --host */
|
|
{
|
|
dynstr_append(&path_buf, "\nhost = ");
|
|
dynstr_append(&path_buf, opt_host);
|
|
}
|
|
|
|
if (opt_socket)
|
|
{
|
|
dynstr_append(&path_buf, "\nsocket = ");
|
|
dynstr_append(&path_buf, opt_socket);
|
|
}
|
|
|
|
if (opt_port)
|
|
{
|
|
dynstr_append(&path_buf, "\nport = ");
|
|
dynstr_append(&path_buf, opt_port);
|
|
}
|
|
|
|
dynstr_append(&path_buf, "\n");
|
|
|
|
/* Warn if login path already exists */
|
|
if (opt_warn && ((locate_login_path (&file_buf, opt_login_path))
|
|
!= NULL))
|
|
{
|
|
int choice;
|
|
printf ("WARNING : \'%s\' path already exists and will be "
|
|
"overwritten. \n Continue? (Press y|Y for Yes, any "
|
|
"other key for No) : ",
|
|
opt_login_path);
|
|
choice= getchar();
|
|
|
|
if (choice != (int) 'y' && choice != (int) 'Y')
|
|
goto done; /* skip */
|
|
}
|
|
|
|
/* Remove the login path. */
|
|
remove_login_path(&file_buf, opt_login_path);
|
|
|
|
/* Append the new login path to the file buffer. */
|
|
dynstr_append(&file_buf, path_buf.str);
|
|
|
|
if (encrypt_and_write_file(&file_buf) == -1)
|
|
goto error;
|
|
|
|
done:
|
|
dynstr_free(&file_buf);
|
|
dynstr_free(&path_buf);
|
|
DBUG_RETURN(0);
|
|
|
|
error:
|
|
dynstr_free(&file_buf);
|
|
dynstr_free(&path_buf);
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
static int remove_command(void) {
|
|
DBUG_ENTER("remove_command");
|
|
|
|
DYNAMIC_STRING file_buf, path_buf;
|
|
|
|
init_dynamic_string(&path_buf, "", MY_LINE_MAX, MY_LINE_MAX);
|
|
init_dynamic_string(&file_buf, "", file_size, 3 * MY_LINE_MAX);
|
|
|
|
if (file_size)
|
|
{
|
|
if (read_and_decrypt_file(&file_buf) == -1)
|
|
goto error;
|
|
}
|
|
else
|
|
goto done; /* Nothing to remove, skip.. */
|
|
|
|
/* Warn if no login path is specified. */
|
|
if (opt_warn &&
|
|
((locate_login_path (&file_buf, opt_login_path)) != NULL) &&
|
|
(login_path_specified == FALSE)
|
|
)
|
|
{
|
|
int choice;
|
|
printf ("WARNING : No login path specified, so options from the default "
|
|
"login path will be removed.\nContinue? (Press y|Y for Yes, "
|
|
"any other key for No) : ");
|
|
choice= getchar();
|
|
|
|
if (choice != (int) 'y' && choice != (int) 'Y')
|
|
goto done; /* skip */
|
|
}
|
|
|
|
remove_options(&file_buf, opt_login_path);
|
|
|
|
if (encrypt_and_write_file(&file_buf) == -1)
|
|
goto error;
|
|
|
|
done:
|
|
dynstr_free(&file_buf);
|
|
dynstr_free(&path_buf);
|
|
DBUG_RETURN(0);
|
|
|
|
error:
|
|
dynstr_free(&file_buf);
|
|
dynstr_free(&path_buf);
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
/**
|
|
Execute 'print' command.
|
|
|
|
@param void
|
|
|
|
@return -1 Error
|
|
0 Success
|
|
*/
|
|
|
|
static int print_command(void)
|
|
{
|
|
DBUG_ENTER("print_command");
|
|
DYNAMIC_STRING file_buf;
|
|
|
|
init_dynamic_string(&file_buf, "", file_size, 3 * MY_LINE_MAX);
|
|
|
|
if (file_size)
|
|
{
|
|
if (read_and_decrypt_file(&file_buf) == -1)
|
|
goto error;
|
|
}
|
|
else
|
|
goto done; /* Nothing to print, skip..*/
|
|
|
|
print_login_path(&file_buf, opt_login_path);
|
|
|
|
done:
|
|
dynstr_free(&file_buf);
|
|
DBUG_RETURN(0);
|
|
|
|
error:
|
|
dynstr_free(&file_buf);
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
|
|
/**
|
|
Create the login file if it does not exist, check
|
|
and set its permissions and modes.
|
|
|
|
@param void
|
|
|
|
@return TRUE Error
|
|
FALSE Success
|
|
*/
|
|
|
|
static my_bool check_and_create_login_file(void)
|
|
{
|
|
DBUG_ENTER("check_and_create_login_file");
|
|
|
|
MY_STAT stat_info;
|
|
|
|
// This is a hack to make it compile. File permissions are different on Windows.
|
|
#ifdef _WIN32
|
|
#define S_IRUSR 00400
|
|
#define S_IWUSR 00200
|
|
#define S_IRWXU 00700
|
|
#define S_IRWXG 00070
|
|
#define S_IRWXO 00007
|
|
#endif
|
|
|
|
const int access_flag= (O_RDWR | O_BINARY);
|
|
const ushort create_mode= (S_IRUSR | S_IWUSR );
|
|
|
|
/* Get the login file name. */
|
|
if (! my_default_get_login_file(my_login_file, sizeof(my_login_file)))
|
|
{
|
|
my_perror("failed to set login file name");
|
|
goto error;
|
|
}
|
|
|
|
/*
|
|
NOTE : MYSQL_TEST_LOGIN_FILE env must be a full path,
|
|
where the directory structure must exist. However the
|
|
login file will be created if it does not exist.
|
|
*/
|
|
#ifdef _WIN32
|
|
if (! (getenv("MYSQL_TEST_LOGIN_FILE")))
|
|
{
|
|
/* Check if 'MySQL' directory is in place. */
|
|
MY_STAT stat_info_dir;
|
|
char login_dir[FN_REFLEN];
|
|
size_t size;
|
|
|
|
dirname_part(login_dir, my_login_file, &size);
|
|
/* Remove the trailing '\' */
|
|
if (is_directory_separator(login_dir[-- size]))
|
|
login_dir[size]= 0;
|
|
|
|
/* Now check if directory exists? */
|
|
if ( my_stat(login_dir, &stat_info_dir, MYF(0)))
|
|
{
|
|
verbose_msg("%s directory exists.\n", login_dir);
|
|
}
|
|
else
|
|
{
|
|
/* Create the login directory. */
|
|
verbose_msg("%s directory doesn't exist, creating it.\n", login_dir);
|
|
if (my_mkdir(login_dir, 0, MYF(0)))
|
|
{
|
|
my_perror("failed to create the directory");
|
|
goto error;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Check for login file's existence and permissions (0600). */
|
|
if (my_stat(my_login_file, &stat_info, MYF(0)))
|
|
{
|
|
verbose_msg("File exists.\n");
|
|
|
|
file_size= (size_t) stat_info.st_size;
|
|
|
|
#ifdef _WIN32
|
|
if (1)
|
|
#else
|
|
if (!(stat_info.st_mode & (S_IXUSR | S_IRWXG | S_IRWXO)))
|
|
#endif
|
|
{
|
|
verbose_msg("File has the required permission.\nOpening the file.\n");
|
|
if ((g_fd= my_open(my_login_file, access_flag, MYF(MY_WME))) == -1)
|
|
{
|
|
my_perror("couldn't open the file");
|
|
goto error;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
verbose_msg("File does not have the required permission.\n");
|
|
printf ("WARNING : Login file does not have the required"
|
|
" file permissions.\nPlease set the mode to 600 &"
|
|
" run the command again.\n");
|
|
goto error;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
verbose_msg("File does not exist.\nCreating login file.\n");
|
|
if ((g_fd= my_create(my_login_file, create_mode, access_flag,
|
|
MYF(MY_WME))) == -1)
|
|
{
|
|
my_perror("couldn't create the login file");
|
|
goto error;
|
|
}
|
|
else
|
|
{
|
|
verbose_msg("Login file created.\n");
|
|
my_close(g_fd, MYF(MY_WME));
|
|
verbose_msg("Opening the file.\n");
|
|
|
|
if((g_fd= my_open(my_login_file, access_flag, MYF(MY_WME))) == -1)
|
|
{
|
|
my_perror("couldn't open the file");
|
|
goto error;
|
|
}
|
|
file_size= 0;
|
|
}
|
|
}
|
|
|
|
if (file_size == 0)
|
|
{
|
|
generate_login_key();
|
|
if(add_header() == -1)
|
|
goto error;
|
|
}
|
|
else
|
|
{
|
|
if (read_login_key() == -1)
|
|
goto error;
|
|
}
|
|
|
|
DBUG_RETURN(FALSE);
|
|
|
|
error:
|
|
DBUG_RETURN(TRUE);
|
|
}
|
|
|
|
|
|
/**
|
|
Print options under the specified login path. If '--all'
|
|
option is used, print all the optins stored in the login
|
|
file.
|
|
|
|
@param file_buf [in] Buffer storing the unscrambled login
|
|
file contents.
|
|
@param path_name [in] Path name.
|
|
|
|
@return void
|
|
|
|
*/
|
|
|
|
static void print_login_path(DYNAMIC_STRING *file_buf, const char *path_name)
|
|
{
|
|
DBUG_ENTER("print_login_path");
|
|
|
|
char *start= NULL, *end= NULL, temp= '\0';
|
|
|
|
if (file_buf->length == 0)
|
|
goto done; /* Nothing to print. */
|
|
|
|
if (opt_all)
|
|
{
|
|
start= file_buf->str;
|
|
end= file_buf->str + file_buf->length;
|
|
}
|
|
else
|
|
{
|
|
start= locate_login_path(file_buf, path_name);
|
|
if (! start)
|
|
/* login path not found, skip..*/
|
|
goto done;
|
|
|
|
end= strstr(start, "\n[");
|
|
}
|
|
|
|
if (end)
|
|
{
|
|
temp= *end;
|
|
*end= '\0';
|
|
}
|
|
|
|
mask_password_and_print(start);
|
|
|
|
if (temp != '\0')
|
|
*end= temp;
|
|
|
|
done:
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/**
|
|
Print the specified buffer by masking the actual
|
|
password string.
|
|
|
|
@param buf [in] Buffer to be printed.
|
|
|
|
@raturn void
|
|
*/
|
|
|
|
static void mask_password_and_print(char *buf)
|
|
{
|
|
DBUG_ENTER("mask_password_and_print");
|
|
const char *password_str= "\npassword = ", *mask = "*****";
|
|
char *next= NULL;
|
|
|
|
while ((next= strstr(buf, password_str)) != NULL)
|
|
{
|
|
while ( *buf != 0 && buf != next)
|
|
putc( *(buf ++), stdout);
|
|
printf("%s", password_str);
|
|
printf("%s\n", mask);
|
|
if (*buf == '\n') /* Move past \n' */
|
|
buf ++;
|
|
|
|
/* Ignore the password. */
|
|
while( *buf && *(buf ++) != '\n')
|
|
{}
|
|
|
|
if ( !opt_all)
|
|
break;
|
|
}
|
|
|
|
/* Now print the rest of the buffer. */
|
|
while ( *buf) putc( *(buf ++), stdout);
|
|
// And a new line.. if required.
|
|
if (* (buf - 1) != '\n')
|
|
putc('\n', stdout);
|
|
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/**
|
|
Remove multiple options from a login path.
|
|
*/
|
|
static void remove_options(DYNAMIC_STRING *file_buf, const char *path_name)
|
|
{
|
|
/* If nope of the options are specified remove the entire path. */
|
|
if (!opt_remove_host && !opt_remove_pass && !opt_remove_user
|
|
&& !opt_remove_socket && !opt_remove_port)
|
|
{
|
|
remove_login_path(file_buf, path_name);
|
|
return;
|
|
}
|
|
|
|
if (opt_remove_user)
|
|
remove_option(file_buf, path_name, "user");
|
|
|
|
if (opt_remove_pass)
|
|
remove_option(file_buf, path_name, "password");
|
|
|
|
if (opt_remove_host)
|
|
remove_option(file_buf, path_name, "host");
|
|
|
|
if (opt_remove_socket)
|
|
remove_option(file_buf, path_name, "socket");
|
|
|
|
if (opt_remove_port)
|
|
remove_option(file_buf, path_name, "port");
|
|
}
|
|
|
|
|
|
/**
|
|
Remove an option from a login path.
|
|
*/
|
|
static void remove_option(DYNAMIC_STRING *file_buf, const char *path_name,
|
|
const char* option_name)
|
|
{
|
|
DBUG_ENTER("remove_option");
|
|
|
|
char *start= NULL, *end= NULL;
|
|
char *search_str;
|
|
size_t search_len, shift_len;
|
|
bool option_found= FALSE;
|
|
|
|
search_str= (char *) my_malloc(PSI_NOT_INSTRUMENTED,
|
|
(uint) strlen(option_name) + 2, MYF(MY_WME));
|
|
sprintf(search_str, "\n%s", option_name);
|
|
|
|
if ((start= locate_login_path(file_buf, path_name)) == NULL)
|
|
/* login path was not found, skip.. */
|
|
goto done;
|
|
|
|
end= strstr(start, "\n["); /* Next path. */
|
|
|
|
if (end)
|
|
search_len= end - start;
|
|
else
|
|
search_len= file_buf->length - (start - file_buf->str);
|
|
|
|
while(search_len > 1)
|
|
{
|
|
if (!strncmp(start, search_str, strlen(search_str)))
|
|
{
|
|
/* Option found. */
|
|
end= start;
|
|
while(*(++ end) != '\n')
|
|
{}
|
|
option_found= TRUE;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
/* Move to next line. */
|
|
while( (-- search_len > 1) && (*(++ start) != '\n'))
|
|
{}
|
|
}
|
|
}
|
|
|
|
if (option_found)
|
|
{
|
|
shift_len= file_buf->length - (end - file_buf->str);
|
|
|
|
file_buf->length -= (end - start);
|
|
|
|
while(shift_len --)
|
|
*(start ++)= *(end ++);
|
|
*start= '\0';
|
|
}
|
|
|
|
done:
|
|
my_free(search_str);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/**
|
|
Remove the specified login path from the login file.
|
|
|
|
@param file_buf [in] Buffer storing the unscrambled login
|
|
file contents.
|
|
@param path_name [in] Path name.
|
|
|
|
@return void
|
|
|
|
*/
|
|
|
|
static void remove_login_path(DYNAMIC_STRING *file_buf, const char *path_name)
|
|
{
|
|
DBUG_ENTER("remove_login_path");
|
|
|
|
char *start=NULL, *end= NULL;
|
|
int to_move, len, diff;
|
|
|
|
if((start= locate_login_path(file_buf, path_name)) == NULL)
|
|
/* login path was not found, skip.. */
|
|
goto done;
|
|
|
|
end= strstr(start, "\n[");
|
|
|
|
if (end)
|
|
{
|
|
end ++; /* Move past '\n' */
|
|
len= ((diff= (start - end)) > 0) ? diff : - diff;
|
|
to_move= file_buf->length - (end - file_buf->str) ;
|
|
}
|
|
else
|
|
{
|
|
*start= '\0';
|
|
file_buf->length= ((diff= (file_buf->str - start)) > 0) ? diff : - diff;
|
|
goto done;
|
|
}
|
|
|
|
while(to_move --)
|
|
*(start ++)= *(end ++);
|
|
|
|
*start= '\0';
|
|
file_buf->length -= len;
|
|
|
|
done:
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
/**
|
|
Remove all the contents from the login file.
|
|
|
|
@param gen_key [in] Flag to control the generation of
|
|
a new key.
|
|
|
|
@return -1 Error
|
|
0 Success
|
|
*/
|
|
|
|
static int reset_login_file(bool gen_key)
|
|
{
|
|
DBUG_ENTER("reset_login_file");
|
|
|
|
if (my_chsize(g_fd, 0, 0, MYF(MY_WME)))
|
|
{
|
|
verbose_msg("Error while truncating the file.\n");
|
|
goto error;
|
|
}
|
|
|
|
/* Seek to the beginning of the file. */
|
|
if (my_seek(g_fd, 0L, SEEK_SET, MYF(MY_WME) == MY_FILEPOS_ERROR))
|
|
goto error; /* Error. */
|
|
|
|
if (gen_key)
|
|
generate_login_key(); /* Generate a new key. */
|
|
|
|
if (add_header() == -1)
|
|
goto error;
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
error:
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
/**
|
|
Find the specified login path in the login file buffer
|
|
and return the starting address.
|
|
|
|
@param file_buf [in] Buffer storing the unscrambled login
|
|
file contents.
|
|
@param path_name [in] Path name.
|
|
|
|
@return If found, the starting address of the
|
|
login path, NULL otherwise.
|
|
*/
|
|
|
|
static char* locate_login_path(DYNAMIC_STRING *file_buf, const char *path_name)
|
|
{
|
|
DBUG_ENTER("locate_login_path");
|
|
|
|
char *addr= NULL;
|
|
DYNAMIC_STRING dy_path_name;
|
|
|
|
init_dynamic_string(&dy_path_name, "", 512, 512);
|
|
|
|
dynstr_append(&dy_path_name, "\n[");
|
|
dynstr_append(&dy_path_name, path_name);
|
|
dynstr_append(&dy_path_name, "]");
|
|
|
|
/* First check if it is the very first login path. */
|
|
if (file_buf->str == strstr(file_buf->str, dy_path_name.str + 1))
|
|
addr= file_buf->str;
|
|
/* If not, scan through the file. */
|
|
else
|
|
{
|
|
addr= strstr(file_buf->str, dy_path_name.str);
|
|
if (addr)
|
|
addr ++; /* Move past '\n' */
|
|
}
|
|
|
|
dynstr_free(&dy_path_name);
|
|
DBUG_RETURN(addr);
|
|
}
|
|
|
|
|
|
/**
|
|
Encrypt the file buffer and write it to the login file.
|
|
|
|
@param file_buf [in] Buffer storing the unscrambled login
|
|
file contents.
|
|
|
|
@return -1 Error
|
|
0 Success
|
|
|
|
@note The contents of the file buffer are encrypted
|
|
on a line-by-line basis with each line having
|
|
the following format :
|
|
[<first 4 bytes store cipher-length>|<Next cipher-length
|
|
bytes store actual cipher>]
|
|
*/
|
|
|
|
static int encrypt_and_write_file(DYNAMIC_STRING *file_buf)
|
|
{
|
|
DBUG_ENTER("encrypt_and_write_file");
|
|
|
|
my_bool done= FALSE;
|
|
char cipher[MY_LINE_MAX], *tmp= NULL;
|
|
uint bytes_read=0, len= 0;
|
|
int enc_len= 0; // Can be negative.
|
|
|
|
if (reset_login_file(0) == -1)
|
|
goto error;
|
|
|
|
/* Move past key first. */
|
|
if (my_seek(g_fd, MY_LOGIN_HEADER_LEN, SEEK_SET, MYF(MY_WME))
|
|
!= (MY_LOGIN_HEADER_LEN))
|
|
goto error; /* Error while seeking. */
|
|
|
|
|
|
tmp= &file_buf->str[bytes_read];
|
|
|
|
while(! done)
|
|
{
|
|
len= 0;
|
|
|
|
while(*tmp++ != '\n')
|
|
if (len < (file_buf->length - bytes_read))
|
|
len ++;
|
|
else
|
|
{
|
|
done= TRUE;
|
|
break;
|
|
}
|
|
|
|
if (done)
|
|
break;
|
|
|
|
if ((enc_len= my_aes_get_size(len + 1, my_aes_128_ecb)) >
|
|
(MY_LINE_MAX - (int)MAX_CIPHER_STORE_LEN))
|
|
{
|
|
my_perror("A parameter to mysql_config_editor exceeds the maximum "
|
|
"accepted length. Please review the data you've supplied "
|
|
"and try to shorten them permissible length.\n");
|
|
goto error;
|
|
}
|
|
|
|
if (encrypt_buffer(&file_buf->str[bytes_read], ++len,
|
|
cipher + MAX_CIPHER_STORE_LEN, enc_len) < 0)
|
|
goto error;
|
|
|
|
bytes_read += len;
|
|
|
|
/* Store cipher length first. */
|
|
int4store(cipher, enc_len);
|
|
|
|
if ((my_write(g_fd, (const uchar *)cipher, enc_len + MAX_CIPHER_STORE_LEN,
|
|
MYF(MY_WME))) != (enc_len + MAX_CIPHER_STORE_LEN))
|
|
goto error;
|
|
}
|
|
|
|
verbose_msg("Successfully written encrypted data to the login file.\n");
|
|
|
|
/* Update file_size */
|
|
file_size= bytes_read;
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
error:
|
|
my_perror("couldn't encrypt the file");
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
|
|
/**
|
|
Read the login file, unscramble its contents and store
|
|
them into the file buffer.
|
|
|
|
@param file_buf [in] Buffer for storing the unscrambled login
|
|
file contents.
|
|
|
|
@return -1 Error
|
|
0 Success
|
|
*/
|
|
|
|
static int read_and_decrypt_file(DYNAMIC_STRING *file_buf)
|
|
{
|
|
DBUG_ENTER("read_and_decrypt_file");
|
|
|
|
char cipher[MY_LINE_MAX], plain[MY_LINE_MAX];
|
|
uchar len_buf[MAX_CIPHER_STORE_LEN];
|
|
int cipher_len= 0, dec_len= 0;
|
|
|
|
/* Move past key first. */
|
|
if (my_seek(g_fd, MY_LOGIN_HEADER_LEN, SEEK_SET, MYF(MY_WME))
|
|
!= (MY_LOGIN_HEADER_LEN))
|
|
goto error; /* Error while seeking. */
|
|
|
|
/* First read the length of the cipher. */
|
|
while (my_read(g_fd, len_buf, MAX_CIPHER_STORE_LEN,
|
|
MYF(MY_WME)) == MAX_CIPHER_STORE_LEN)
|
|
{
|
|
cipher_len= sint4korr(len_buf);
|
|
|
|
if (cipher_len > MY_LINE_MAX)
|
|
goto error;
|
|
|
|
/* Now read 'cipher_len' bytes from the file. */
|
|
if ((int) my_read(g_fd, (uchar *) cipher, cipher_len, MYF(MY_WME)) == cipher_len)
|
|
{
|
|
if ((dec_len= decrypt_buffer(cipher, cipher_len, plain)) < 0)
|
|
goto error;
|
|
|
|
plain[dec_len]= 0;
|
|
dynstr_append(file_buf, plain);
|
|
}
|
|
}
|
|
|
|
verbose_msg("Successfully decrypted the login file.\n");
|
|
DBUG_RETURN(0);
|
|
|
|
error:
|
|
my_perror("couldn't decrypt the file");
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
|
|
/**
|
|
Encrypt the given plain text.
|
|
|
|
@param plain [in] Plain text to be encrypted.
|
|
@param plain_len [in] Length of the plain text.
|
|
@param cipher [out] Encrypted cipher text.
|
|
|
|
@return -1 if error encountered,
|
|
length encrypted, otherwise.
|
|
*/
|
|
|
|
static int encrypt_buffer(const char *plain, int plain_len, char cipher[], const int aes_len)
|
|
{
|
|
DBUG_ENTER("encrypt_buffer");
|
|
|
|
if (my_aes_encrypt((const unsigned char *) plain, plain_len,
|
|
(unsigned char *) cipher,
|
|
(const unsigned char *) my_key, LOGIN_KEY_LEN,
|
|
my_aes_128_ecb, NULL) == aes_len)
|
|
DBUG_RETURN(aes_len);
|
|
|
|
verbose_msg("Error! Couldn't encrypt the buffer.\n");
|
|
DBUG_RETURN(-1); /* Error */
|
|
}
|
|
|
|
|
|
/**
|
|
Decrypt the given cipher text.
|
|
|
|
@param cipher [in] Cipher text to be decrypted.
|
|
@param cipher_len [in] Length of the cipher text.
|
|
@param plain [out] Decrypted plain text.
|
|
|
|
@return -1 if error encountered,
|
|
length decrypted, otherwise.
|
|
*/
|
|
|
|
static int decrypt_buffer(const char *cipher, int cipher_len, char plain[])
|
|
{
|
|
DBUG_ENTER("decrypt_buffer");
|
|
int aes_length;
|
|
|
|
if ((aes_length= my_aes_decrypt((const unsigned char *) cipher, cipher_len,
|
|
(unsigned char *) plain,
|
|
(const unsigned char *) my_key,
|
|
LOGIN_KEY_LEN,
|
|
my_aes_128_ecb, NULL)) > 0)
|
|
DBUG_RETURN(aes_length);
|
|
|
|
verbose_msg("Error! Couldn't decrypt the buffer.\n");
|
|
DBUG_RETURN(-1); /* Error */
|
|
}
|
|
|
|
|
|
/**
|
|
Add unused bytes alongwith the to the login key
|
|
to the login file.
|
|
|
|
@return -1 if error encountered,
|
|
length written, otherwise.
|
|
*/
|
|
|
|
static int add_header(void)
|
|
{
|
|
DBUG_ENTER("add_header");
|
|
|
|
/* Reserved for future use. */
|
|
const char unused[]= {'\0','\0','\0','\0'};
|
|
|
|
/* Write 'unused' bytes first. */
|
|
if ((my_write(g_fd, (const uchar *) unused, 4, MYF(MY_WME))) != 4)
|
|
goto error;
|
|
|
|
/* Write the login key. */
|
|
if ((my_write(g_fd, (const uchar *)my_key, LOGIN_KEY_LEN, MYF(MY_WME)))
|
|
!= LOGIN_KEY_LEN)
|
|
goto error;
|
|
|
|
verbose_msg("Key successfully written to the file.\n");
|
|
DBUG_RETURN(MY_LOGIN_HEADER_LEN);
|
|
|
|
error:
|
|
my_perror("file write operation failed");
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
|
|
/**
|
|
Algorithm to generate key.
|
|
*/
|
|
|
|
void generate_login_key()
|
|
{
|
|
DBUG_ENTER("generate_login_key");
|
|
struct rand_struct rnd;
|
|
|
|
verbose_msg("Generating a new key.\n");
|
|
/* Get a sequence of random non-printable ASCII */
|
|
for (uint i= 0; i < LOGIN_KEY_LEN; i++)
|
|
my_key[i]= (char)((int)(my_rnd_ssl(&rnd) * 100000) % 32);
|
|
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
/**
|
|
Read the stored login key.
|
|
|
|
@return -1 Error
|
|
0 Success
|
|
*/
|
|
|
|
static int read_login_key(void)
|
|
{
|
|
DBUG_ENTER("read_login_key");
|
|
|
|
verbose_msg("Reading the login key.\n");
|
|
/* Move past the unused buffer. */
|
|
if (my_seek(g_fd, 4, SEEK_SET, MYF(MY_WME)) != 4)
|
|
goto error; /* Error while seeking. */
|
|
|
|
if (my_read(g_fd, (uchar *)my_key, LOGIN_KEY_LEN, MYF(MY_WME))
|
|
!= LOGIN_KEY_LEN)
|
|
goto error; /* Error while reading. */
|
|
|
|
verbose_msg("Login key read successfully.\n");
|
|
DBUG_RETURN(0);
|
|
|
|
error:
|
|
my_perror("file read operation failed");
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
|
|
static void verbose_msg(const char *fmt, ...)
|
|
{
|
|
DBUG_ENTER("verbose_msg");
|
|
va_list args;
|
|
|
|
if (!opt_verbose)
|
|
DBUG_VOID_RETURN;
|
|
|
|
va_start(args, fmt);
|
|
vfprintf(stderr, fmt, args);
|
|
va_end(args);
|
|
fflush(stderr);
|
|
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
static void my_perror(const char *msg)
|
|
{
|
|
char errbuf[MYSYS_STRERROR_SIZE];
|
|
|
|
if (errno == 0)
|
|
fprintf(stderr, "%s\n", (msg) ? msg : "");
|
|
else
|
|
fprintf(stderr, "%s : %s\n", (msg) ? msg : "",
|
|
my_strerror(errbuf, sizeof(errbuf), errno));
|
|
// reset errno
|
|
errno= 0;
|
|
}
|
|
|
|
static void usage_command(int command)
|
|
{
|
|
print_version();
|
|
puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2012"));
|
|
puts("MySQL Configuration Utility.");
|
|
printf("\nDescription: %s\n", command_data[command].description);
|
|
printf("Usage: %s [program options] [%s [command options]]\n",
|
|
my_progname, command_data[command].name);
|
|
my_print_help(command_data[command].options);
|
|
my_print_variables(command_data[command].options);
|
|
}
|
|
|
|
|
|
static void usage_program(void)
|
|
{
|
|
print_version();
|
|
puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2012"));
|
|
puts("MySQL Configuration Utility.");
|
|
printf("Usage: %s [program options] [command [command options]]\n",
|
|
my_progname);
|
|
my_print_help(my_program_long_options);
|
|
my_print_variables(my_program_long_options);
|
|
puts("\nWhere command can be any one of the following :\n\
|
|
set [command options] Sets user name/password/host name/socket/port\n\
|
|
for a given login path (section).\n\
|
|
remove [command options] Remove a login path from the login file.\n\
|
|
print [command options] Print all the options for a specified\n\
|
|
login path.\n\
|
|
reset [command options] Deletes the contents of the login file.\n\
|
|
help Display this usage/help information.\n");
|
|
}
|
|
|
|
|
|
static void print_version(void) {
|
|
printf ("%s Ver %s Distrib %s, for %s on %s\n", my_progname,
|
|
MYSQL_CONFIG_EDITOR_VERSION, MYSQL_SERVER_VERSION,
|
|
SYSTEM_TYPE, MACHINE_TYPE);
|
|
}
|
|
|