|
- /*
- Copyright (c) 2012, 2021, Oracle and/or its affiliates.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License, version 2.0,
- as published by the Free Software Foundation.
-
- This program is also distributed with certain software (including
- but not limited to OpenSSL) that is licensed under separate terms,
- as designated in a particular file or component or in included license
- documentation. The authors of MySQL hereby grant you an additional
- permission to link the program and your derivative works with the
- separately licensed software that they have included with MySQL.
-
- 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, version 2.0, 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 NDEBUG
- {"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(COPYRIGHT_NOTICE_STONEDB_BEGIN_YEAR));
- 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(COPYRIGHT_NOTICE_STONEDB_BEGIN_YEAR));
- 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);
- }
|