MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
mysql_config_editor.cc
Go to the documentation of this file.
1 /*
2  Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
25 /* ORACLE_WELCOME_COPYRIGHT_NOTICE */
26 #include "my_config.h"
27 #include <welcome_copyright_notice.h>
28 #include <signal.h>
29 #include <my_dir.h>
30 #include <my_rnd.h>
31 #include "my_aes.h"
32 #include "client_priv.h"
33 #include "my_default.h"
34 #include "my_default_priv.h"
35 
36 #define MYSQL_CONFIG_EDITOR_VERSION "1.0"
37 #define MY_LINE_MAX 4096
38 #define MAX_COMMAND_LIMIT 100
39 /*
40  Header length for the login file.
41  4-byte (unused) + LOGIN_KEY_LEN
42  */
43 #define MY_LOGIN_HEADER_LEN (4 + LOGIN_KEY_LEN)
44 
45 static int g_fd;
46 
47 /*
48  Length of the contents in login file
49  excluding the header part.
50 */
51 static size_t file_size;
52 static char *opt_user= NULL, *opt_password= NULL, *opt_host=NULL,
53  *opt_login_path= NULL, *opt_socket= NULL, *opt_port= NULL;
54 
55 static char my_login_file[FN_REFLEN];
56 static char my_key[LOGIN_KEY_LEN];
57 
58 static my_bool opt_verbose, opt_all, tty_password= 0, opt_warn,
59  opt_remove_host, opt_remove_pass, opt_remove_user,
60  opt_remove_socket, opt_remove_port, login_path_specified= FALSE;
61 
62 static int execute_commands(int command);
63 static int set_command(void);
64 static int remove_command(void);
65 static int print_command(void);
66 static void print_login_path(DYNAMIC_STRING *file_buf, const char *path_name);
67 static void remove_login_path(DYNAMIC_STRING *file_buf, const char *path_name);
68 static char* locate_login_path(DYNAMIC_STRING *file_buf, const char *path_name);
69 static my_bool check_and_create_login_file(void);
70 static void mask_password_and_print(char *buf);
71 static int reset_login_file(bool gen_key);
72 
73 static int encrypt_buffer(const char *plain, int plain_len, char cipher[]);
74 static int decrypt_buffer(const char *cipher, int cipher_len, char plain[]);
75 static int encrypt_and_write_file(DYNAMIC_STRING *file_buf);
76 static int read_and_decrypt_file(DYNAMIC_STRING *file_buf);
77 static int do_handle_options(int argc, char *argv[]);
78 static void remove_options(DYNAMIC_STRING *file_buf, const char *path_name);
79 static void remove_option(DYNAMIC_STRING *file_buf, const char *path_name,
80  const char* option_name);
81 void generate_login_key(void);
82 static int read_login_key(void);
83 static int add_header(void);
84 static void my_perror(const char *msg);
85 
86 static void verbose_msg(const char *fmt, ...);
87 static void print_version(void);
88 static void usage_program(void);
89 static void usage_command(int command);
90 extern "C" my_bool get_one_option(int optid, const struct my_option *opt,
91  char *argument);
92 
93 enum commands {
94  MY_CONFIG_SET,
95  MY_CONFIG_REMOVE,
96  MY_CONFIG_PRINT,
97  MY_CONFIG_RESET,
98  MY_CONFIG_HELP
99 };
100 
102  const int id;
103  const char *name;
104  const char *description;
105  my_option *options;
106  my_bool (*get_one_option_func)(int optid,
107  const struct my_option *opt,
108  char *argument);
109 };
110 
111 
112 /* mysql_config_editor utility options. */
113 static struct my_option my_program_long_options[]=
114 {
115 #ifndef DBUG_OFF
116  {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
117  0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
118 #endif
119  {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG,
120  NO_ARG, 0, 0, 0, 0, 0, 0},
121  {"verbose", 'v', "Write more information.", &opt_verbose,
122  &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
123  {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
124  NO_ARG, 0, 0, 0, 0, 0, 0},
125  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
126 };
127 
128 /* Command-specific options. */
129 
130 /* SET command options. */
131 static struct my_option my_set_command_options[]=
132 {
133  {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG,
134  NO_ARG, 0, 0, 0, 0, 0, 0},
135  {"host", 'h', "Host name to be entered into the login file.", &opt_host,
136  &opt_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
137  {"login-path", 'G', "Name of the login path to use in the login file. "
138  "(Default : client)", &opt_login_path, &opt_login_path, 0, GET_STR,
139  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
140  {"password", 'p', "Prompt for password to be entered into the login file.",
141  0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
142  {"user", 'u', "User name to be entered into the login file.", &opt_user,
143  &opt_user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
144  {"socket", 'S', "Socket path to be entered into login file.", &opt_socket,
145  &opt_socket, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
146  {"port", 'P', "Port number to be entered into login file.", &opt_port,
147  &opt_port, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
148  {"warn", 'w', "Warn and ask for confirmation if set command attempts to "
149  "overwrite an existing login path (enabled by default).",
150  &opt_warn, &opt_warn, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
151  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
152 };
153 
154 /* REMOVE command options. */
155 static struct my_option my_remove_command_options[]=
156 {
157  {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG,
158  NO_ARG, 0, 0, 0, 0, 0, 0},
159  {"host", 'h', "Remove host name from the login path.",
160  &opt_remove_host, &opt_remove_host, 0, GET_BOOL, NO_ARG, 0, 0, 0,
161  0, 0, 0},
162  {"login-path", 'G', "Name of the login path from which options to "
163  "be removed (entire path would be removed if none of user, password, "
164  "host, socket, or port options are specified). (Default : client)",
165  &opt_login_path, &opt_login_path, 0, GET_STR, REQUIRED_ARG,
166  0, 0, 0, 0, 0, 0},
167  {"password", 'p', "Remove password from the login path.",
168  &opt_remove_pass, &opt_remove_pass, 0, GET_BOOL, NO_ARG, 0, 0, 0,
169  0, 0, 0},
170  {"user", 'u', "Remove user name from the login path.", &opt_remove_user,
171  &opt_remove_user, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
172  {"warn", 'w', "Warn and ask for confirmation if remove command attempts "
173  "to remove the default login path (client) if no login path is specified "
174  "(enabled by default).", &opt_warn, &opt_warn, 0, GET_BOOL, NO_ARG, 1,
175  0, 0, 0, 0, 0},
176  {"socket", 'S', "Remove socket path from the login path.", &opt_remove_socket,
177  &opt_remove_socket, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
178  {"port", 'P', "Remove port number from the login path.", &opt_remove_port,
179  &opt_remove_port, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
180  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
181 };
182 
183 /* PRINT command options. */
184 static struct my_option my_print_command_options[]=
185 {
186  {"all", OPT_CONFIG_ALL, "Used with print command to print all login paths.",
187  &opt_all, &opt_all, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
188  {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG,
189  NO_ARG, 0, 0, 0, 0, 0, 0},
190  {"login-path", 'G', "Name of the login path to use in the login file. "
191  "(Default : client)", &opt_login_path, &opt_login_path, 0, GET_STR,
192  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
193  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
194 };
195 
196 /* RESET command options. */
197 static struct my_option my_reset_command_options[]=
198 {
199  {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG,
200  NO_ARG, 0, 0, 0, 0, 0, 0},
201  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
202 };
203 
204 /* HELP command options. */
205 static struct my_option my_help_command_options[]=
206 {
207  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
208 };
209 
210 my_bool
211 my_program_get_one_option(int optid,
212  const struct my_option *opt __attribute__((unused)),
213  char *argument)
214 {
215  switch(optid) {
216  case '#':
217  DBUG_PUSH(argument ? argument : "d:t:o,/tmp/mysql_config_editor.trace");
218  break;
219  case 'V':
220  print_version();
221  exit(0);
222  break;
223  case '?':
224  usage_program();
225  exit(0);
226  break;
227  }
228  return 0;
229 }
230 
231 my_bool
232 my_set_command_get_one_option(int optid,
233  const struct my_option *opt __attribute__((unused)),
234  char *argument)
235 {
236  switch(optid) {
237  case 'p':
238  tty_password= 1;
239  break;
240  case 'G':
241  if (login_path_specified)
242  {
243  /* Error, we do not support multiple login paths. */
244  my_perror("Error: Use of multiple login paths is not supported. "
245  "Exiting..");
246  return 1;
247  }
248  login_path_specified= TRUE;
249  break;
250  case '?':
251  usage_command(MY_CONFIG_SET);
252  exit(0);
253  break;
254  }
255  return 0;
256 }
257 
258 my_bool
259 my_remove_command_get_one_option(int optid,
260  const struct my_option *opt __attribute__((unused)),
261  char *argument)
262 {
263  switch(optid) {
264  case 'G':
265  if (login_path_specified)
266  {
267  /* Error, we do not support multiple login paths. */
268  my_perror("Error: Use of multiple login paths is not supported. "
269  "Exiting..");
270  return 1;
271  }
272  login_path_specified= TRUE;
273  break;
274  case '?':
275  usage_command(MY_CONFIG_REMOVE);
276  exit(0);
277  break;
278  }
279  return 0;
280 }
281 
282 my_bool
283 my_print_command_get_one_option(int optid,
284  const struct my_option *opt __attribute__((unused)),
285  char *argument)
286 {
287  switch(optid) {
288  case 'G':
289  if (login_path_specified)
290  {
291  /* Error, we do not support multiple login paths. */
292  my_perror("Error: Use of multiple login paths is not supported. "
293  "Exiting..");
294  return 1;
295  }
296  login_path_specified= TRUE;
297  break;
298  case '?':
299  usage_command(MY_CONFIG_PRINT);
300  exit(0);
301  break;
302  }
303  return 0;
304 }
305 
306 my_bool
307 my_reset_command_get_one_option(int optid,
308  const struct my_option *opt __attribute__((unused)),
309  char *argument)
310 {
311  switch(optid) {
312  case '?':
313  usage_command(MY_CONFIG_RESET);
314  exit(0);
315  break;
316  }
317  return 0;
318 }
319 
320 static struct my_command_data command_data[]=
321 {
322  {
323  MY_CONFIG_SET,
324  "set",
325  "Write a login path to the login file.",
326  my_set_command_options,
327  my_set_command_get_one_option
328  },
329  {
330  MY_CONFIG_REMOVE,
331  "remove",
332  "Remove a login path from the login file.",
333  my_remove_command_options,
334  my_remove_command_get_one_option
335  },
336  {
337  MY_CONFIG_PRINT,
338  "print",
339  "Print the contents of login file in unencrypted form.",
340  my_print_command_options,
341  my_print_command_get_one_option
342  },
343  {
344  MY_CONFIG_RESET,
345  "reset",
346  "Empty the contents of the login file. The file is created\n"
347  "if it does not exist.",
348  my_reset_command_options,
349  my_reset_command_get_one_option
350  },
351  {
352  MY_CONFIG_HELP,
353  "help",
354  "Display a help message and exit.",
355  my_help_command_options,
356  NULL
357  },
358  {
359  0, NULL, NULL, NULL, NULL
360  }
361 };
362 
363 
364 int main(int argc, char *argv[])
365 {
366  MY_INIT(argv[0]);
367  DBUG_ENTER("main");
368  int command, rc= 0;
369 
370  command= do_handle_options(argc, argv);
371 
372  if (command > -1)
373  rc= execute_commands(command);
374 
375  if (rc == -1)
376  {
377  my_perror("operation failed.");
378  DBUG_RETURN(1);
379  }
380  DBUG_RETURN(0);
381 }
382 
383 
390 static int do_handle_options(int argc, char *argv[])
391 {
392  DBUG_ENTER("do_handle_options");
393 
394  const char *command_list[MAX_COMMAND_LIMIT + 1];
395  char **saved_argv= argv;
396  char **argv_cmd;
397  char *ptr; /* for free. */
398  int argc_cmd;
399  int rc, i, command= -1;
400 
401  if (argc < 2)
402  {
403  usage_program();
404  exit(1);
405  }
406 
407  if (!(ptr= (char *) my_malloc((argc + 2) * sizeof(char *),
408  MYF(MY_WME))))
409  goto error;
410 
411  /* Handle program options. */
412 
413  /* Prepare a list of supported commands to be used by my_handle_options(). */
414  for (i= 0; (command_data[i].name != NULL) && (i < MAX_COMMAND_LIMIT); i++)
415  command_list[i]= (char *) command_data[i].name;
416  command_list[i]= NULL;
417 
418  if ((rc= my_handle_options(&argc, &argv, my_program_long_options,
419  my_program_get_one_option, command_list)))
420  exit(rc);
421 
422  if (argc == 0) /* No command specified. */
423  goto done;
424 
425  for (i= 0; command_data[i].name != NULL; i++)
426  {
427  if (!strcmp(command_data[i].name, argv[0]))
428  {
429  command= i;
430  break;
431  }
432  }
433 
434  if (command == -1)
435  goto error;
436 
437  /* Handle command options. */
438 
439  argv_cmd= (char **)ptr;
440  argc_cmd= argc + 1;
441 
442  /* Prepare a command line (argv) using the rest of the options. */
443  argv_cmd[0]= saved_argv[0];
444  memcpy((uchar *) (argv_cmd + 1), (uchar *) (argv),
445  (argc * sizeof(char *)));
446  argv_cmd[argc_cmd]= 0;
447 
448  if ((rc= handle_options(&argc_cmd, &argv_cmd,
449  command_data[command].options,
450  command_data[command].get_one_option_func)))
451  exit(rc);
452 
453  /* Do not allow multiple commands. */
454  if ( argc_cmd > 1)
455  goto error;
456 
457  /* If NULL, set it to 'client' (default) */
458  if (!opt_login_path)
459  opt_login_path= my_strdup("client", MYF(MY_WME));
460 
461 done:
462  my_free(ptr);
463  DBUG_RETURN(command);
464 
465 error:
466  my_free(ptr);
467  usage_program();
468  exit(1);
469 }
470 
471 
472 static int execute_commands(int command)
473 {
474  DBUG_ENTER("execute_commands");
475  int rc= 0;
476 
477  if ((rc= check_and_create_login_file()))
478  goto done;
479 
480  switch(command_data[command].id) {
481  case MY_CONFIG_SET :
482  verbose_msg("Executing set command.\n");
483  rc= set_command();
484  break;
485 
486  case MY_CONFIG_REMOVE :
487  verbose_msg("Executing remove command.\n");
488  rc= remove_command();
489  break;
490 
491  case MY_CONFIG_PRINT :
492  verbose_msg("Executing print command.\n");
493  rc= print_command();
494  break;
495 
496  case MY_CONFIG_RESET :
497  verbose_msg("Resetting login file.\n");
498  rc= reset_login_file(1);
499  break;
500 
501  case MY_CONFIG_HELP :
502  verbose_msg("Printing usage info.\n");
503  usage_program();
504  break;
505 
506  default :
507  my_perror("unknown command.");
508  exit(1);
509  }
510 
511  my_close(g_fd, MYF(MY_WME));
512 
513 done:
514  DBUG_RETURN(rc);
515 }
516 
517 
527 static int set_command(void)
528 {
529  DBUG_ENTER("set_command");
530 
531  DYNAMIC_STRING file_buf, path_buf;
532 
533  init_dynamic_string(&path_buf, "", MY_LINE_MAX, MY_LINE_MAX);
534  init_dynamic_string(&file_buf, "", file_size, 3 * MY_LINE_MAX);
535 
536  if (tty_password)
537  opt_password= get_tty_password(NullS);
538 
539  if (file_size)
540  {
541  if (read_and_decrypt_file(&file_buf) == -1)
542  goto error;
543  }
544 
545  dynstr_append(&path_buf, "["); /* --login=path */
546  if (opt_login_path)
547  dynstr_append(&path_buf, opt_login_path);
548  else
549  dynstr_append(&path_buf, "client");
550  dynstr_append(&path_buf, "]");
551 
552  if (opt_user) /* --user */
553  {
554  dynstr_append(&path_buf, "\nuser = ");
555  dynstr_append(&path_buf, opt_user);
556  }
557 
558  if (opt_password) /* --password */
559  {
560  dynstr_append(&path_buf, "\npassword = ");
561  dynstr_append(&path_buf, opt_password);
562  }
563 
564  if (opt_host) /* --host */
565  {
566  dynstr_append(&path_buf, "\nhost = ");
567  dynstr_append(&path_buf, opt_host);
568  }
569 
570  if (opt_socket)
571  {
572  dynstr_append(&path_buf, "\nsocket = ");
573  dynstr_append(&path_buf, opt_socket);
574  }
575 
576  if (opt_port)
577  {
578  dynstr_append(&path_buf, "\nport = ");
579  dynstr_append(&path_buf, opt_port);
580  }
581 
582  dynstr_append(&path_buf, "\n");
583 
584  /* Warn if login path already exists */
585  if (opt_warn && ((locate_login_path (&file_buf, opt_login_path))
586  != NULL))
587  {
588  int choice;
589  printf ("WARNING : \'%s\' path already exists and will be "
590  "overwritten. \n Continue? (Press y|Y for Yes, any "
591  "other key for No) : ",
592  opt_login_path);
593  choice= getchar();
594 
595  if (choice != (int) 'y' && choice != (int) 'Y')
596  goto done; /* skip */
597  }
598 
599  /* Remove the login path. */
600  remove_login_path(&file_buf, opt_login_path);
601 
602  /* Append the new login path to the file buffer. */
603  dynstr_append(&file_buf, path_buf.str);
604 
605  if (encrypt_and_write_file(&file_buf) == -1)
606  goto error;
607 
608 done:
609  dynstr_free(&file_buf);
610  dynstr_free(&path_buf);
611  DBUG_RETURN(0);
612 
613 error:
614  dynstr_free(&file_buf);
615  dynstr_free(&path_buf);
616  DBUG_RETURN(-1);
617 }
618 
619 static int remove_command(void) {
620  DBUG_ENTER("remove_command");
621 
622  DYNAMIC_STRING file_buf, path_buf;
623 
624  init_dynamic_string(&path_buf, "", MY_LINE_MAX, MY_LINE_MAX);
625  init_dynamic_string(&file_buf, "", file_size, 3 * MY_LINE_MAX);
626 
627  if (file_size)
628  {
629  if (read_and_decrypt_file(&file_buf) == -1)
630  goto error;
631  }
632  else
633  goto done; /* Nothing to remove, skip.. */
634 
635  /* Warn if no login path is specified. */
636  if (opt_warn &&
637  ((locate_login_path (&file_buf, opt_login_path)) != NULL) &&
638  (login_path_specified == FALSE)
639  )
640  {
641  int choice;
642  printf ("WARNING : No login path specified, so options from the default "
643  "login path will be removed.\nContinue? (Press y|Y for Yes, "
644  "any other key for No) : ");
645  choice= getchar();
646 
647  if (choice != (int) 'y' && choice != (int) 'Y')
648  goto done; /* skip */
649  }
650 
651  remove_options(&file_buf, opt_login_path);
652 
653  if (encrypt_and_write_file(&file_buf) == -1)
654  goto error;
655 
656 done:
657  dynstr_free(&file_buf);
658  dynstr_free(&path_buf);
659  DBUG_RETURN(0);
660 
661 error:
662  dynstr_free(&file_buf);
663  dynstr_free(&path_buf);
664  DBUG_RETURN(-1);
665 }
666 
676 static int print_command(void)
677 {
678  DBUG_ENTER("print_command");
679  DYNAMIC_STRING file_buf;
680 
681  init_dynamic_string(&file_buf, "", file_size, 3 * MY_LINE_MAX);
682 
683  if (file_size)
684  {
685  if (read_and_decrypt_file(&file_buf) == -1)
686  goto error;
687  }
688  else
689  goto done; /* Nothing to print, skip..*/
690 
691  print_login_path(&file_buf, opt_login_path);
692 
693 done:
694  dynstr_free(&file_buf);
695  DBUG_RETURN(0);
696 
697 error:
698  dynstr_free(&file_buf);
699  DBUG_RETURN(-1);
700 }
701 
702 
713 static my_bool check_and_create_login_file(void)
714 {
715  DBUG_ENTER("check_and_create_login_file");
716 
717  MY_STAT stat_info;
718 
719 // This is a hack to make it compile. File permissions are different on Windows.
720 #ifdef _WIN32
721 #define S_IRUSR 00400
722 #define S_IWUSR 00200
723 #define S_IRWXU 00700
724 #define S_IRWXG 00070
725 #define S_IRWXO 00007
726 #endif
727 
728  const int access_flag= (O_RDWR | O_BINARY);
729  const ushort create_mode= (S_IRUSR | S_IWUSR );
730 
731  /* Get the login file name. */
732  if (! my_default_get_login_file(my_login_file, sizeof(my_login_file)))
733  {
734  my_perror("failed to set login file name");
735  goto error;
736  }
737 
738  /*
739  NOTE : MYSQL_TEST_LOGIN_FILE env must be a full path,
740  where the directory structure must exist. However the
741  login file will be created if it does not exist.
742  */
743 #ifdef _WIN32
744  if (! (getenv("MYSQL_TEST_LOGIN_FILE")))
745  {
746  /* Check if 'MySQL' directory is in place. */
747  MY_STAT stat_info_dir;
748  char login_dir[FN_REFLEN];
749  size_t size;
750 
751  dirname_part(login_dir, my_login_file, &size);
752  /* Remove the trailing '\' */
753  if (login_dir[-- size] == FN_LIBCHAR)
754  login_dir[size]= 0;
755 
756  /* Now check if directory exists? */
757  if ( my_stat(login_dir, &stat_info_dir, MYF(0)))
758  {
759  verbose_msg("%s directory exists.\n", login_dir);
760  }
761  else
762  {
763  /* Create the login directory. */
764  verbose_msg("%s directory doesn't exist, creating it.\n", login_dir);
765  if (my_mkdir(login_dir, 0, MYF(0)))
766  {
767  my_perror("failed to create the directory");
768  goto error;
769  }
770  }
771  }
772 #endif
773 
774  /* Check for login file's existence and permissions (0600). */
775  if (my_stat(my_login_file, &stat_info, MYF(0)))
776  {
777  verbose_msg("File exists.\n");
778 
779  file_size= stat_info.st_size;
780 
781 #ifdef _WIN32
782  if (1)
783 #else
784  if (!(stat_info.st_mode & (S_IXUSR | S_IRWXG | S_IRWXO)))
785 #endif
786  {
787  verbose_msg("File has the required permission.\nOpening the file.\n");
788  if ((g_fd= my_open(my_login_file, access_flag, MYF(MY_WME))) == -1)
789  {
790  my_perror("couldn't open the file");
791  goto error;
792  }
793  }
794  else
795  {
796  verbose_msg("File does not have the required permission.\n");
797  printf ("WARNING : Login file does not have the required"
798  " file permissions.\nPlease set the mode to 600 &"
799  " run the command again.\n");
800  goto error;
801  }
802  }
803  else
804  {
805  verbose_msg("File does not exist.\nCreating login file.\n");
806  if ((g_fd= my_create(my_login_file, create_mode, access_flag,
807  MYF(MY_WME)) == -1))
808  {
809  my_perror("couldn't create the login file");
810  goto error;
811  }
812  else
813  {
814  verbose_msg("Login file created.\n");
815  verbose_msg("Opening the file.\n");
816 
817  if((g_fd= my_open(my_login_file, access_flag, MYF(MY_WME))) == -1)
818  {
819  my_perror("couldn't open the file");
820  goto error;
821  }
822  file_size= 0;
823  }
824  }
825 
826  if (file_size == 0)
827  {
829  if(add_header() == -1)
830  goto error;
831  }
832  else
833  {
834  if (read_login_key() == -1)
835  goto error;
836  }
837 
838  DBUG_RETURN(0);
839 
840 error:
841  DBUG_RETURN(-1);
842 }
843 
844 
858 static void print_login_path(DYNAMIC_STRING *file_buf, const char *path_name)
859 {
860  DBUG_ENTER("print_login_path");
861 
862  char *start= NULL, *end= NULL, temp= '\0';
863 
864  if (file_buf->length == 0)
865  goto done; /* Nothing to print. */
866 
867  if (opt_all)
868  {
869  start= file_buf->str;
870  end= file_buf->str + file_buf->length;
871  }
872  else
873  {
874  start= locate_login_path(file_buf, path_name);
875  if (! start)
876  /* login path not found, skip..*/
877  goto done;
878 
879  end= strstr(start, "\n[");
880  }
881 
882  if (end)
883  {
884  temp= *end;
885  *end= '\0';
886  }
887 
888  mask_password_and_print(start);
889 
890  if (temp != '\0')
891  *end= temp;
892 
893 done:
894  DBUG_VOID_RETURN;
895 }
896 
897 
907 static void mask_password_and_print(char *buf)
908 {
909  DBUG_ENTER("mask_password_and_print");
910  const char *password_str= "\npassword = ", *mask = "*****";
911  char *next= NULL;
912 
913  while ((next= strstr(buf, password_str)) != NULL)
914  {
915  while ( *buf != 0 && buf != next)
916  putc( *(buf ++), stdout);
917  printf("%s", password_str);
918  printf("%s\n", mask);
919  if (*buf == '\n') /* Move past \n' */
920  buf ++;
921 
922  /* Ignore the password. */
923  while( *buf && *(buf ++) != '\n')
924  {}
925 
926  if ( !opt_all)
927  break;
928  }
929 
930  /* Now print the rest of the buffer. */
931  while ( *buf) putc( *(buf ++), stdout);
932  // And a new line.. if required.
933  if (* (buf - 1) != '\n')
934  putc('\n', stdout);
935 
936  DBUG_VOID_RETURN;
937 }
938 
939 
943 static void remove_options(DYNAMIC_STRING *file_buf, const char *path_name)
944 {
945  /* If nope of the options are specified remove the entire path. */
946  if (!opt_remove_host && !opt_remove_pass && !opt_remove_user
947  && !opt_remove_socket && !opt_remove_port)
948  {
949  remove_login_path(file_buf, path_name);
950  return;
951  }
952 
953  if (opt_remove_user)
954  remove_option(file_buf, path_name, "user");
955 
956  if (opt_remove_pass)
957  remove_option(file_buf, path_name, "password");
958 
959  if (opt_remove_host)
960  remove_option(file_buf, path_name, "host");
961 
962  if (opt_remove_socket)
963  remove_option(file_buf, path_name, "socket");
964 
965  if (opt_remove_port)
966  remove_option(file_buf, path_name, "port");
967 }
968 
969 
973 static void remove_option(DYNAMIC_STRING *file_buf, const char *path_name,
974  const char* option_name)
975 {
976  DBUG_ENTER("remove_option");
977 
978  char *start= NULL, *end= NULL;
979  char *search_str;
980  int search_len, shift_len;
981  bool option_found= FALSE;
982 
983  search_str= (char *) my_malloc((uint) strlen(option_name) + 2, MYF(MY_WME));
984  sprintf(search_str, "\n%s", option_name);
985 
986  if ((start= locate_login_path(file_buf, path_name)) == NULL)
987  /* login path was not found, skip.. */
988  goto done;
989 
990  end= strstr(start, "\n["); /* Next path. */
991 
992  if (end)
993  search_len= end - start;
994  else
995  search_len= file_buf->length - (start - file_buf->str);
996 
997  while(search_len > 1)
998  {
999  if (!strncmp(start, search_str, strlen(search_str)))
1000  {
1001  /* Option found. */
1002  end= start;
1003  while(*(++ end) != '\n')
1004  {}
1005  option_found= TRUE;
1006  break;
1007  }
1008  else
1009  {
1010  /* Move to next line. */
1011  while( (-- search_len > 1) && (*(++ start) != '\n'))
1012  {}
1013  }
1014  }
1015 
1016  if (option_found)
1017  {
1018  shift_len= file_buf->length - (end - file_buf->str);
1019 
1020  file_buf->length -= (end - start);
1021 
1022  while(shift_len --)
1023  *(start ++)= *(end ++);
1024  *start= '\0';
1025  }
1026 
1027 done:
1028  my_free(search_str);
1029  DBUG_VOID_RETURN;
1030 }
1031 
1032 
1044 static void remove_login_path(DYNAMIC_STRING *file_buf, const char *path_name)
1045 {
1046  DBUG_ENTER("remove_login_path");
1047 
1048  char *start=NULL, *end= NULL;
1049  int tot_len, len, diff;
1050 
1051  if((start= locate_login_path(file_buf, path_name)) == NULL)
1052  /* login path was not found, skip.. */
1053  goto done;
1054 
1055  end= strstr(start, "\n[");
1056 
1057  if (end)
1058  {
1059  end ++; /* Move past '\n' */
1060  len= ((diff= (start - end)) > 0) ? diff : - diff;
1061  tot_len= file_buf->length - len ;
1062  }
1063  else
1064  {
1065  *start= '\0';
1066  file_buf->length= ((diff= (file_buf->str - start)) > 0) ? diff : - diff;
1067  goto done;
1068  }
1069 
1070  while(tot_len --)
1071  *(start ++)= *(end ++);
1072 
1073  *start= '\0';
1074  file_buf->length -= len;
1075 
1076 done:
1077  DBUG_VOID_RETURN;
1078 }
1079 
1090 static int reset_login_file(bool gen_key)
1091 {
1092  DBUG_ENTER("reset_login_file");
1093 
1094  if (my_chsize(g_fd, 0, 0, MYF(MY_WME)))
1095  {
1096  verbose_msg("Error while truncating the file.\n");
1097  goto error;
1098  }
1099 
1100  /* Seek to the beginning of the file. */
1101  if (my_seek(g_fd, 0L, SEEK_SET, MYF(MY_WME) == MY_FILEPOS_ERROR))
1102  goto error; /* Error. */
1103 
1104  if (gen_key)
1105  generate_login_key(); /* Generate a new key. */
1106 
1107  if (add_header() == -1)
1108  goto error;
1109 
1110  DBUG_RETURN(0);
1111 
1112 error:
1113  DBUG_RETURN(0);
1114 }
1115 
1116 
1129 static char* locate_login_path(DYNAMIC_STRING *file_buf, const char *path_name)
1130 {
1131  DBUG_ENTER("locate_login_path");
1132 
1133  char *addr= NULL;
1134  DYNAMIC_STRING dy_path_name;
1135 
1136  init_dynamic_string(&dy_path_name, "", 512, 512);
1137 
1138  dynstr_append(&dy_path_name, "\n[");
1139  dynstr_append(&dy_path_name, path_name);
1140  dynstr_append(&dy_path_name, "]");
1141 
1142  /* First check if it is the very first login path. */
1143  if (file_buf->str == strstr(file_buf->str, dy_path_name.str + 1))
1144  addr= file_buf->str;
1145  /* If not, scan through the file. */
1146  else
1147  {
1148  addr= strstr(file_buf->str, dy_path_name.str);
1149  if (addr)
1150  addr ++; /* Move past '\n' */
1151  }
1152 
1153  dynstr_free(&dy_path_name);
1154  DBUG_RETURN(addr);
1155 }
1156 
1157 
1174 static int encrypt_and_write_file(DYNAMIC_STRING *file_buf)
1175 {
1176  DBUG_ENTER("encrypt_and_write_file");
1177 
1178  my_bool done= FALSE;
1179  char cipher[MY_LINE_MAX], *tmp= NULL;
1180  uint bytes_read=0, len= 0;
1181  int enc_len= 0; // Can be negative.
1182 
1183  if (reset_login_file(0) == -1)
1184  goto error;
1185 
1186  /* Move past key first. */
1187  if (my_seek(g_fd, MY_LOGIN_HEADER_LEN, SEEK_SET, MYF(MY_WME))
1188  != (MY_LOGIN_HEADER_LEN))
1189  goto error; /* Error while seeking. */
1190 
1191 
1192  tmp= &file_buf->str[bytes_read];
1193 
1194  while(! done)
1195  {
1196  len= 0;
1197 
1198  while(*tmp++ != '\n')
1199  if (len < (file_buf->length - bytes_read))
1200  len ++;
1201  else
1202  {
1203  done= TRUE;
1204  break;
1205  }
1206 
1207  if (done)
1208  break;
1209 
1210  if ((enc_len= encrypt_buffer(&file_buf->str[bytes_read],
1211  ++ len, cipher + MAX_CIPHER_STORE_LEN)) < 0)
1212  goto error;
1213 
1214  bytes_read += len;
1215 
1216  if (enc_len > MY_LINE_MAX)
1217  goto error;
1218 
1219  /* Store cipher length first. */
1220  int4store(cipher, enc_len);
1221 
1222  if ((my_write(g_fd, (const uchar *)cipher, enc_len + MAX_CIPHER_STORE_LEN,
1223  MYF(MY_WME))) != (enc_len + MAX_CIPHER_STORE_LEN))
1224  goto error;
1225  }
1226 
1227  verbose_msg("Successfully written encrypted data to the login file.\n");
1228 
1229  /* Update file_size */
1230  file_size= bytes_read;
1231 
1232  DBUG_RETURN(0);
1233 
1234 error:
1235  my_perror("couldn't encrypt the file");
1236  DBUG_RETURN(-1);
1237 }
1238 
1239 
1251 static int read_and_decrypt_file(DYNAMIC_STRING *file_buf)
1252 {
1253  DBUG_ENTER("read_and_decrypt_file");
1254 
1255  char cipher[MY_LINE_MAX], plain[MY_LINE_MAX];
1256  uchar len_buf[MAX_CIPHER_STORE_LEN];
1257  int cipher_len= 0, dec_len= 0;
1258 
1259  /* Move past key first. */
1260  if (my_seek(g_fd, MY_LOGIN_HEADER_LEN, SEEK_SET, MYF(MY_WME))
1261  != (MY_LOGIN_HEADER_LEN))
1262  goto error; /* Error while seeking. */
1263 
1264  /* First read the length of the cipher. */
1265  while (my_read(g_fd, len_buf, MAX_CIPHER_STORE_LEN,
1266  MYF(MY_WME)) == MAX_CIPHER_STORE_LEN)
1267  {
1268  cipher_len= sint4korr(len_buf);
1269 
1270  if (cipher_len > MY_LINE_MAX)
1271  goto error;
1272 
1273  /* Now read 'cipher_len' bytes from the file. */
1274  if ((int) my_read(g_fd, (uchar *) cipher, cipher_len, MYF(MY_WME)) == cipher_len)
1275  {
1276  if ((dec_len= decrypt_buffer(cipher, cipher_len, plain)) < 0)
1277  goto error;
1278 
1279  plain[dec_len]= 0;
1280  dynstr_append(file_buf, plain);
1281  }
1282  }
1283 
1284  verbose_msg("Successfully decrypted the login file.\n");
1285  DBUG_RETURN(0);
1286 
1287 error:
1288  my_perror("couldn't decrypt the file");
1289  DBUG_RETURN(-1);
1290 }
1291 
1292 
1304 static int encrypt_buffer(const char *plain, int plain_len, char cipher[])
1305 {
1306  DBUG_ENTER("encrypt_buffer");
1307  int aes_len;
1308 
1309  aes_len= my_aes_get_size(plain_len);
1310 
1311  if (my_aes_encrypt(plain, plain_len, cipher, my_key, LOGIN_KEY_LEN) == aes_len)
1312  DBUG_RETURN(aes_len);
1313 
1314  verbose_msg("Error! Couldn't encrypt the buffer.\n");
1315  DBUG_RETURN(-1); /* Error */
1316 }
1317 
1318 
1330 static int decrypt_buffer(const char *cipher, int cipher_len, char plain[])
1331 {
1332  DBUG_ENTER("decrypt_buffer");
1333  int aes_length;
1334 
1335  if ((aes_length= my_aes_decrypt(cipher, cipher_len, (char *) plain,
1336  my_key, LOGIN_KEY_LEN)) > 0)
1337  DBUG_RETURN(aes_length);
1338 
1339  verbose_msg("Error! Couldn't decrypt the buffer.\n");
1340  DBUG_RETURN(-1); /* Error */
1341 }
1342 
1343 
1352 static int add_header(void)
1353 {
1354  DBUG_ENTER("add_header");
1355 
1356  /* Reserved for future use. */
1357  const char unused[]= {'\0','\0','\0','\0'};
1358 
1359  /* Write 'unused' bytes first. */
1360  if ((my_write(g_fd, (const uchar *) unused, 4, MYF(MY_WME))) != 4)
1361  goto error;
1362 
1363  /* Write the login key. */
1364  if ((my_write(g_fd, (const uchar *)my_key, LOGIN_KEY_LEN, MYF(MY_WME)))
1365  != LOGIN_KEY_LEN)
1366  goto error;
1367 
1368  verbose_msg("Key successfully written to the file.\n");
1369  DBUG_RETURN(MY_LOGIN_HEADER_LEN);
1370 
1371 error:
1372  my_perror("file write operation failed");
1373  DBUG_RETURN(-1);
1374 }
1375 
1376 
1382 {
1383  DBUG_ENTER("generate_login_key");
1384  struct rand_struct rnd;
1385 
1386  verbose_msg("Generating a new key.\n");
1387  /* Get a sequence of random non-printable ASCII */
1388  for (uint i= 0; i < LOGIN_KEY_LEN; i++)
1389  my_key[i]= (char)((int)(my_rnd_ssl(&rnd) * 100000) % 32);
1390 
1391  DBUG_VOID_RETURN;
1392 }
1393 
1401 static int read_login_key(void)
1402 {
1403  DBUG_ENTER("read_login_key");
1404 
1405  verbose_msg("Reading the login key.\n");
1406  /* Move past the unused buffer. */
1407  if (my_seek(g_fd, 4, SEEK_SET, MYF(MY_WME)) != 4)
1408  goto error; /* Error while seeking. */
1409 
1410  if (my_read(g_fd, (uchar *)my_key, LOGIN_KEY_LEN, MYF(MY_WME))
1411  != LOGIN_KEY_LEN)
1412  goto error; /* Error while reading. */
1413 
1414  verbose_msg("Login key read successfully.\n");
1415  DBUG_RETURN(0);
1416 
1417 error:
1418  my_perror("file read operation failed");
1419  DBUG_RETURN(-1);
1420 }
1421 
1422 
1423 static void verbose_msg(const char *fmt, ...)
1424 {
1425  DBUG_ENTER("verbose_msg");
1426  va_list args;
1427 
1428  if (!opt_verbose)
1429  DBUG_VOID_RETURN;
1430 
1431  va_start(args, fmt);
1432  vfprintf(stderr, fmt, args);
1433  va_end(args);
1434  fflush(stderr);
1435 
1436  DBUG_VOID_RETURN;
1437 }
1438 
1439 static void my_perror(const char *msg)
1440 {
1441  char errbuf[MYSYS_STRERROR_SIZE];
1442 
1443  if (errno == 0)
1444  fprintf(stderr, "%s\n", (msg) ? msg : "");
1445  else
1446  fprintf(stderr, "%s : %s\n", (msg) ? msg : "",
1447  my_strerror(errbuf, sizeof(errbuf), errno));
1448  // reset errno
1449  errno= 0;
1450 }
1451 
1452 static void usage_command(int command)
1453 {
1454  print_version();
1455  puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2012"));
1456  puts("MySQL Configuration Utility.");
1457  printf("\nDescription: %s\n", command_data[command].description);
1458  printf("Usage: %s [program options] [%s [command options]]\n",
1459  my_progname, command_data[command].name);
1460  my_print_help(command_data[command].options);
1461  my_print_variables(command_data[command].options);
1462 }
1463 
1464 
1465 static void usage_program(void)
1466 {
1467  print_version();
1468  puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2012"));
1469  puts("MySQL Configuration Utility.");
1470  printf("Usage: %s [program options] [command [command options]]\n",
1471  my_progname);
1472  my_print_help(my_program_long_options);
1473  my_print_variables(my_program_long_options);
1474  puts("\nWhere command can be any one of the following :\n\
1475  set [command options] Sets user name/password/host name/socket/port\n\
1476  for a given login path (section).\n\
1477  remove [command options] Remove a login path from the login file.\n\
1478  print [command options] Print all the options for a specified\n\
1479  login path.\n\
1480  reset [command options] Deletes the contents of the login file.\n\
1481  help Display this usage/help information.\n");
1482 }
1483 
1484 
1485 static void print_version(void) {
1486  printf ("%s Ver %s Distrib %s, for %s on %s\n", my_progname,
1487  MYSQL_CONFIG_EDITOR_VERSION, MYSQL_SERVER_VERSION,
1488  SYSTEM_TYPE, MACHINE_TYPE);
1489 }
1490