1 /* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    Without limiting anything contained in the foregoing, this file,
15    which is part of C Driver for MySQL (Connector/C), is also subject to the
16    Universal FOSS Exception, version 1.0, a copy of which can be found at
17    http://oss.oracle.com/licenses/universal-foss-exception.
18 
19    This program is distributed in the hope that it will be useful,
20    but WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22    GNU General Public License, version 2.0, for more details.
23 
24    You should have received a copy of the GNU General Public License
25    along with this program; if not, write to the Free Software
26    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
27 
28 /****************************************************************************
29  Add all options from files named "group".cnf from the default_directories
30  before the command line arguments.
31  On Windows defaults will also search in the Windows directory for a file
32  called 'group'.ini
33  As long as the program uses the last argument for conflicting
34  options one only have to add a call to "load_defaults" to enable
35  use of default values.
36  pre- and end 'blank space' are removed from options and values. The
37  following escape sequences are recognized in values:  \b \t \n \r \\
38 
39  The following arguments are handled automatically;  If used, they must be
40  first argument on the command line!
41  --no-defaults	; no options are read, except for the ones provided in the
42                   login file.
43  --defaults-file=full-path-to-default-file	; Only this file will be read.
44  --defaults-extra-file=full-path-to-default-file ; Read this file before ~/
45  --defaults-group-suffix  ; Also read groups with concat(group, suffix)
46  --print-defaults	  ; Print the modified command line and exit
47  --login-path=login-path-name ; Read options under login-path-name from
48                                 the login file.
49 ****************************************************************************/
50 
51 #include "../mysys/mysys_priv.h"
52 #include "my_default.h"
53 #include "my_default_priv.h"
54 #include "m_string.h"
55 #include "m_ctype.h"
56 #include <my_dir.h>
57 #include <my_aes.h>
58 #ifdef __WIN__
59 #include <winbase.h>
60 #endif
61 
62 C_MODE_START
63 #ifdef HAVE_PSI_INTERFACE
64 extern PSI_file_key key_file_cnf;
65 #endif
66 C_MODE_END
67 
68 /**
69    arguments separator
70 
71    load_defaults() loads arguments from config file and put them
72    before the arguments from command line, this separator is used to
73    separate the arguments loaded from config file and arguments user
74    provided on command line.
75 
76    Options with value loaded from config file are always in the form
77    '--option=value', while for command line options, the value can be
78    given as the next argument. Thus we used a separator so that
79    handle_options() can distinguish them.
80 
81    Note: any other places that does not need to distinguish them
82    should skip the separator.
83 
84    The content of arguments separator does not matter, one should only
85    check the pointer, use "----args-separator----" here to ease debug
86    if someone misused it.
87 
88    The args seprator will only be added when
89    my_getopt_use_args_seprator is set to TRUE before calling
90    load_defaults();
91 
92    See BUG#25192
93 */
94 static const char *args_separator= "----args-separator----";
set_args_separator(char ** arg)95 inline static void set_args_separator(char** arg)
96 {
97   DBUG_ASSERT(my_getopt_use_args_separator);
98   *arg= (char*)args_separator;
99 }
100 
101 /*
102   This flag indicates that the argument separator string
103   (args_separator) should be added to the list of arguments,
104   in order to separate arguments received from config file
105   and command line.
106 */
107 my_bool my_getopt_use_args_separator= FALSE;
my_getopt_is_args_separator(const char * arg)108 my_bool my_getopt_is_args_separator(const char* arg)
109 {
110   return (arg == args_separator);
111 }
112 const char *my_defaults_file=0;
113 const char *my_defaults_group_suffix=0;
114 const char *my_defaults_extra_file=0;
115 
116 static const char *my_login_path= 0;
117 
118 static char my_defaults_file_buffer[FN_REFLEN];
119 static char my_defaults_extra_file_buffer[FN_REFLEN];
120 
121 static my_bool defaults_already_read= FALSE;
122 
123 /* Which directories are searched for options (and in which order) */
124 
125 #define MAX_DEFAULT_DIRS 7
126 #define DEFAULT_DIRS_SIZE (MAX_DEFAULT_DIRS + 1)  /* Terminate with NULL */
127 static const char **default_directories = NULL;
128 
129 #ifdef __WIN__
130 static const char *f_extensions[]= { ".ini", ".cnf", 0 };
131 #define NEWLINE "\r\n"
132 #else
133 static const char *f_extensions[]= { ".cnf", 0 };
134 #define NEWLINE "\n"
135 #endif
136 
137 static int handle_default_option(void *in_ctx, const char *group_name,
138                                  const char *option);
139 
140 /*
141    This structure defines the context that we pass to callback
142    function 'handle_default_option' used in search_default_file
143    to process each option. This context is used if search_default_file
144    was called from load_defaults.
145 */
146 
147 struct handle_option_ctx
148 {
149    MEM_ROOT *alloc;
150    DYNAMIC_ARRAY *args;
151    TYPELIB *group;
152 };
153 
154 static int search_default_file(Process_option_func func, void *func_ctx,
155                                const char *dir, const char *config_file,
156                                my_bool is_login_file);
157 static int search_default_file_with_ext(Process_option_func func,
158                                         void *func_ctx,
159 					const char *dir, const char *ext,
160                                         const char *config_file,
161                                         int recursion_level,
162                                         my_bool is_login_file);
163 static my_bool mysql_file_getline(char *str, int size, MYSQL_FILE *file,
164                                   my_bool is_login_file);
165 
166 /**
167   Create the list of default directories.
168 
169   @param alloc  MEM_ROOT where the list of directories is stored
170 
171   @details
172   The directories searched, in order, are:
173   - Windows:     GetSystemWindowsDirectory()
174   - Windows:     GetWindowsDirectory()
175   - Windows:     C:/
176   - Windows:     Directory above where the executable is located
177   - Unix:        /etc/
178   - Unix:        /etc/mysql/
179   - Unix:        --sysconfdir=<path> (compile-time option)
180   - ALL:         getenv("MYSQL_HOME")
181   - ALL:         --defaults-extra-file=<path> (run-time option)
182   - Unix:        ~/
183 
184   On all systems, if a directory is already in the list, it will be moved
185   to the end of the list.  This avoids reading defaults files multiple times,
186   while ensuring the correct precedence.
187 
188   @retval NULL  Failure (out of memory, probably)
189   @retval other Pointer to NULL-terminated array of default directories
190 */
191 
192 static const char **init_default_directories(MEM_ROOT *alloc);
193 
194 
195 static char *remove_end_comment(char *ptr);
196 
197 
198 /*
199   Expand a file name so that the current working directory is added if
200   the name is relative.
201 
202   RETURNS
203    0   All OK
204    2   Out of memory or path too long
205    3   Not able to get working directory
206  */
207 
208 static int
fn_expand(const char * filename,char * result_buf)209 fn_expand(const char *filename, char *result_buf)
210 {
211   char dir[FN_REFLEN];
212   const int flags= MY_UNPACK_FILENAME | MY_SAFE_PATH | MY_RELATIVE_PATH;
213   DBUG_ENTER("fn_expand");
214   DBUG_PRINT("enter", ("filename: %s, result_buf: 0x%lx",
215                        filename, (unsigned long) result_buf));
216   if (my_getwd(dir, sizeof(dir), MYF(0)))
217     DBUG_RETURN(3);
218   DBUG_PRINT("debug", ("dir: %s", dir));
219   if (fn_format(result_buf, filename, dir, "", flags) == NULL)
220     DBUG_RETURN(2);
221   DBUG_PRINT("return", ("result: %s", result_buf));
222   DBUG_RETURN(0);
223 }
224 
225 /*
226   Process config files in default directories.
227 
228   SYNOPSIS
229   my_search_option_files()
230   conf_file                   Basename for configuration file to search for.
231                               If this is a path, then only this file is read.
232   argc                        Pointer to argc of original program
233   argv                        Pointer to argv of original program
234   args_used                   Pointer to variable for storing the number of
235                               arguments used.
236   func                        Pointer to the function to process options
237   func_ctx                    It's context. Usually it is the structure to
238                               store additional options.
239   default_directories         List of default directories.
240   found_no_defaults           TRUE, if --no-defaults is specified.
241 
242   DESCRIPTION
243     Process the default options from argc & argv
244     Read through each found config file looks and calls 'func' to process
245     each option. This function also reads options from login file.
246 
247   NOTES
248     --defaults-group-suffix is only processed if we are called from
249     load_defaults().
250 
251 
252   RETURN
253     0  ok
254     1  given cinf_file doesn't exist
255     2  out of memory
256     3  Can't get current working directory
257 
258     The global variable 'my_defaults_group_suffix' is updated with value for
259     --defaults_group_suffix
260 */
261 
my_search_option_files(const char * conf_file,int * argc,char *** argv,uint * args_used,Process_option_func func,void * func_ctx,const char ** default_directories,my_bool is_login_file,my_bool found_no_defaults)262 int my_search_option_files(const char *conf_file, int *argc, char ***argv,
263                            uint *args_used, Process_option_func func,
264                            void *func_ctx, const char **default_directories,
265                            my_bool is_login_file, my_bool found_no_defaults)
266 {
267   const char **dirs, *forced_default_file, *forced_extra_defaults;
268   int error= 0;
269   DBUG_ENTER("my_search_option_files");
270 
271   /* Skip for login file. */
272   if (! is_login_file)
273   {
274     /* Check if we want to force the use a specific default file */
275     *args_used+= get_defaults_options(*argc - *args_used, *argv + *args_used,
276                                       (char **) &forced_default_file,
277                                       (char **) &forced_extra_defaults,
278                                       (char **) &my_defaults_group_suffix,
279                                       (char **) &my_login_path, found_no_defaults);
280 
281     if (! my_defaults_group_suffix)
282       my_defaults_group_suffix= getenv("MYSQL_GROUP_SUFFIX");
283 
284     if (forced_extra_defaults && !defaults_already_read)
285     {
286       int error= fn_expand(forced_extra_defaults,
287                            my_defaults_extra_file_buffer);
288       if (error)
289         DBUG_RETURN(error);
290 
291       my_defaults_extra_file= my_defaults_extra_file_buffer;
292     }
293 
294     if (forced_default_file && !defaults_already_read)
295     {
296       int error= fn_expand(forced_default_file, my_defaults_file_buffer);
297       if (error)
298         DBUG_RETURN(error);
299       my_defaults_file= my_defaults_file_buffer;
300     }
301 
302     defaults_already_read= TRUE;
303 
304     /*
305       We can only handle 'defaults-group-suffix' if we are called from
306       load_defaults() as otherwise we can't know the type of 'func_ctx'
307     */
308 
309     if (my_defaults_group_suffix && func == handle_default_option)
310     {
311       /* Handle --defaults-group-suffix= */
312       uint i;
313       const char **extra_groups;
314       const size_t instance_len= strlen(my_defaults_group_suffix);
315       struct handle_option_ctx *ctx= (struct handle_option_ctx*) func_ctx;
316       char *ptr;
317       TYPELIB *group= ctx->group;
318 
319       if (!(extra_groups=
320             (const char**)alloc_root(ctx->alloc,
321                                      (2*group->count+1)*sizeof(char*))))
322         DBUG_RETURN(2);
323 
324       for (i= 0; i < group->count; i++)
325       {
326         size_t len;
327         extra_groups[i]= group->type_names[i];  /** copy group */
328 
329         len= strlen(extra_groups[i]);
330         if (!(ptr= (char *) alloc_root(ctx->alloc,
331                                        (uint) (len + instance_len + 1))))
332           DBUG_RETURN(2);
333 
334         extra_groups[i+group->count]= ptr;
335 
336         /** Construct new group */
337         memcpy(ptr, extra_groups[i], len);
338         memcpy(ptr+len, my_defaults_group_suffix, instance_len+1);
339       }
340 
341       group->count*= 2;
342       group->type_names= extra_groups;
343       group->type_names[group->count]= 0;
344     }
345   }
346   else if (my_login_path && func == handle_default_option)
347   {
348     /* Handle --login_path= */
349     uint i;
350     size_t len;
351     const char **extra_groups;
352     size_t instance_len= 0;
353     struct handle_option_ctx *ctx= (struct handle_option_ctx*) func_ctx;
354     char *ptr;
355     TYPELIB *group= ctx->group;
356 
357     if (!(extra_groups= (const char**)alloc_root(ctx->alloc,
358                                                  (group->count + 3)
359                                                  * sizeof(char *))))
360       DBUG_RETURN(2);
361 
362     for (i= 0; i < group->count; i++)
363     {
364       extra_groups[i]= group->type_names[i];    /** copy group */
365     }
366 
367     extra_groups[i]= my_login_path;
368 
369     if (my_defaults_group_suffix && func == handle_default_option)
370     {
371       instance_len= strlen(my_defaults_group_suffix);
372       len= strlen(extra_groups[i]);
373 
374       if (!(ptr= (char *) alloc_root(ctx->alloc,
375                                      (uint) (len + instance_len + 1))))
376         DBUG_RETURN(2);
377 
378       extra_groups[i + 1]= ptr;
379 
380       /** Construct new group */
381       memcpy(ptr, extra_groups[i], len);
382       memcpy(ptr+len, my_defaults_group_suffix, instance_len + 1);
383       group->count += 1;
384     }
385 
386     group->count += 1;
387     group->type_names= extra_groups;
388     group->type_names[group->count]= 0;
389   }
390 
391   // If conf_file is an absolute path, we only read it
392   if (dirname_length(conf_file))
393   {
394     if ((error= search_default_file(func, func_ctx, NullS, conf_file,
395                                     is_login_file)) < 0)
396     goto err;
397   }
398   // If my defaults file is set (from a previous run), we read it
399   else if (my_defaults_file)
400   {
401     if ((error= search_default_file_with_ext(func, func_ctx, "", "",
402                                              my_defaults_file, 0,
403                                              is_login_file)) < 0)
404       goto err;
405     if (error > 0)
406     {
407       fprintf(stderr, "Could not open required defaults file: %s\n",
408               my_defaults_file);
409       goto err;
410     }
411   }
412   else if (! found_no_defaults)
413   {
414     for (dirs= default_directories ; *dirs; dirs++)
415     {
416       if (**dirs)
417       {
418        if (search_default_file(func, func_ctx, *dirs, conf_file,
419                                is_login_file) < 0)
420         goto err;
421       }
422       else if (my_defaults_extra_file)
423       {
424         if ((error= search_default_file_with_ext(func, func_ctx, "", "",
425                                                  my_defaults_extra_file, 0,
426                                                  is_login_file)) < 0)
427           goto err;				/* Fatal error */
428         if (error > 0)
429         {
430           fprintf(stderr, "Could not open required defaults file: %s\n",
431                   my_defaults_extra_file);
432           goto err;
433         }
434       }
435     }
436   }
437 
438   DBUG_RETURN(0);
439 
440 err:
441   fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
442   DBUG_RETURN(1);
443 }
444 
445 
446 /*
447   The option handler for load_defaults.
448 
449   SYNOPSIS
450     handle_deault_option()
451     in_ctx                  Handler context. In this case it is a
452                             handle_option_ctx structure.
453     group_name              The name of the group the option belongs to.
454     option                  The very option to be processed. It is already
455                             prepared to be used in argv (has -- prefix). If it
456                             is NULL, we are handling a new group (section).
457 
458   DESCRIPTION
459     This handler checks whether a group is one of the listed and adds an option
460     to the array if yes. Some other handler can record, for instance, all
461     groups and their options, not knowing in advance the names and amount of
462     groups.
463 
464   RETURN
465     0 - ok
466     1 - error occured
467 */
468 
handle_default_option(void * in_ctx,const char * group_name,const char * option)469 static int handle_default_option(void *in_ctx, const char *group_name,
470                                  const char *option)
471 {
472   char *tmp;
473   struct handle_option_ctx *ctx= (struct handle_option_ctx *) in_ctx;
474 
475   if (!option)
476     return 0;
477 
478   if (find_type((char *)group_name, ctx->group, FIND_TYPE_NO_PREFIX))
479   {
480     if (!(tmp= (char *) alloc_root(ctx->alloc, strlen(option) + 1)))
481       return 1;
482     if (insert_dynamic(ctx->args, &tmp))
483       return 1;
484     strmov(tmp, option);
485   }
486 
487   return 0;
488 }
489 
490 
491 /*
492   Gets options from the command line, however if --no-defaults
493   option is used, --defaults-file & --defaults-extra-file options
494   would be ignored.
495 
496   SYNOPSIS
497     get_defaults_options()
498     argc			Pointer to argc of original program
499     argv			Pointer to argv of original program
500     defaults                    --defaults-file option
501     extra_defaults              --defaults-extra-file option
502     group_suffix                --defaults-group-suffix option
503     login_path                  --login-path option
504 
505   RETURN
506     # Number of arguments used from *argv
507       defaults and extra_defaults will be set to option of the appropriate
508       items of argv array, or to NULL if there are no such options
509 */
510 
get_defaults_options(int argc,char ** argv,char ** defaults,char ** extra_defaults,char ** group_suffix,char ** login_path,my_bool found_no_defaults)511 int get_defaults_options(int argc, char **argv,
512                          char **defaults,
513                          char **extra_defaults,
514                          char **group_suffix,
515                          char **login_path,
516                          my_bool found_no_defaults)
517 {
518   int org_argc= argc, prev_argc= 0, default_option_count= 0;
519   *defaults= *extra_defaults= *group_suffix= *login_path= 0;
520 
521   while (argc >= 2 && argc != prev_argc)
522   {
523     /* Skip program name or previously handled argument */
524     argv++;
525     prev_argc= argc;                            /* To check if we found */
526     /* --no-defaults is always the first option. */
527     if (is_prefix(*argv,"--no-defaults") && ! default_option_count)
528     {
529        argc--;
530        default_option_count ++;
531        continue;
532     }
533     if (!*defaults && is_prefix(*argv, "--defaults-file=") && ! found_no_defaults)
534     {
535       *defaults= *argv + sizeof("--defaults-file=")-1;
536        argc--;
537        default_option_count ++;
538        continue;
539     }
540     if (!*extra_defaults && is_prefix(*argv, "--defaults-extra-file=")
541         && ! found_no_defaults)
542     {
543       *extra_defaults= *argv + sizeof("--defaults-extra-file=")-1;
544       argc--;
545       default_option_count ++;
546       continue;
547     }
548     if (!*group_suffix && is_prefix(*argv, "--defaults-group-suffix="))
549     {
550       *group_suffix= *argv + sizeof("--defaults-group-suffix=")-1;
551       argc--;
552       default_option_count ++;
553       continue;
554     }
555     if (!*login_path && is_prefix(*argv, "--login-path="))
556     {
557       *login_path= *argv + sizeof("--login-path=")-1;
558       argc--;
559       default_option_count ++;
560       continue;
561     }
562   }
563   return org_argc - argc;
564 }
565 
566 /*
567   Wrapper around my_load_defaults() for interface compatibility.
568 
569   SYNOPSIS
570     load_defaults()
571     conf_file			Basename for configuration file to search for.
572     				If this is a path, then only this file is read.
573     groups			Which [group] entrys to read.
574 				Points to an null terminated array of pointers
575     argc			Pointer to argc of original program
576     argv			Pointer to argv of original program
577 
578   NOTES
579 
580     This function is NOT thread-safe as it uses a global pointer internally.
581     See also notes for my_load_defaults().
582 
583   RETURN
584     0 ok
585     1 The given conf_file didn't exists
586 */
load_defaults(const char * conf_file,const char ** groups,int * argc,char *** argv)587 int load_defaults(const char *conf_file, const char **groups,
588                   int *argc, char ***argv)
589 {
590   return my_load_defaults(conf_file, groups, argc, argv, &default_directories);
591 }
592 
593 /** A global to turn off or on reading the mylogin file. On by default */
594 my_bool my_defaults_read_login_file= TRUE;
595 /*
596   Read options from configurations files
597 
598   SYNOPSIS
599     my_load_defaults()
600     conf_file			Basename for configuration file to search for.
601     				If this is a path, then only this file is read.
602     groups			Which [group] entrys to read.
603 				Points to an null terminated array of pointers
604     argc			Pointer to argc of original program
605     argv			Pointer to argv of original program
606     default_directories         Pointer to a location where a pointer to the list
607                                 of default directories will be stored
608 
609   IMPLEMENTATION
610 
611    Read options from configuration files and put them BEFORE the arguments
612    that are already in argc and argv.  This way the calling program can
613    easily command line options override options in configuration files
614 
615    NOTES
616     In case of fatal error, the function will print a warning and do
617     exit(1)
618 
619     To free used memory one should call free_defaults() with the argument
620     that was put in *argv
621 
622    RETURN
623      - If successful, 0 is returned. If 'default_directories' is not NULL,
624      a pointer to the array of default directory paths is stored to a location
625      it points to. That stored value must be passed to my_search_option_files()
626      later.
627 
628      - 1 is returned if the given conf_file didn't exist. In this case, the
629      value pointed to by default_directories is undefined.
630 */
631 
632 
my_load_defaults(const char * conf_file,const char ** groups,int * argc,char *** argv,const char *** default_directories)633 int my_load_defaults(const char *conf_file, const char **groups,
634                   int *argc, char ***argv, const char ***default_directories)
635 {
636   DYNAMIC_ARRAY args;
637   TYPELIB group;
638   my_bool found_print_defaults= 0;
639   uint args_used= 0;
640   int error= 0;
641   MEM_ROOT alloc;
642   char *ptr,**res;
643   struct handle_option_ctx ctx;
644   const char **dirs;
645   char my_login_file[FN_REFLEN];
646   my_bool found_no_defaults= false;
647   uint args_sep= my_getopt_use_args_separator ? 1 : 0;
648   DBUG_ENTER("load_defaults");
649 
650   init_alloc_root(&alloc,512,0);
651   if ((dirs= init_default_directories(&alloc)) == NULL)
652     goto err;
653   /*
654     Check if the user doesn't want any default option processing
655     --no-defaults is always the first option
656   */
657   if (*argc >= 2 && !strcmp(argv[0][1], "--no-defaults"))
658     found_no_defaults= TRUE;
659 
660   group.count=0;
661   group.name= "defaults";
662   group.type_names= groups;
663 
664   for (; *groups ; groups++)
665     group.count++;
666 
667   if (my_init_dynamic_array(&args, sizeof(char*),*argc, 32))
668     goto err;
669 
670   ctx.alloc= &alloc;
671   ctx.args= &args;
672   ctx.group= &group;
673 
674   if ((error= my_search_option_files(conf_file, argc, argv,
675                                      &args_used, handle_default_option,
676                                      (void *) &ctx, dirs, false, found_no_defaults)))
677   {
678     delete_dynamic(&args);
679     free_root(&alloc,MYF(0));
680     DBUG_RETURN(error);
681   }
682 
683   if (my_defaults_read_login_file)
684   {
685     /* Read options from login group. */
686     if (my_default_get_login_file(my_login_file, sizeof(my_login_file)) &&
687       (error= my_search_option_files(my_login_file, argc, argv, &args_used,
688                                      handle_default_option, (void *) &ctx,
689                                      dirs, true, found_no_defaults)))
690     {
691       delete_dynamic(&args);
692       free_root(&alloc, MYF(0));
693       DBUG_RETURN(error);
694     }
695   }
696 
697   /*
698     Here error contains <> 0 only if we have a fully specified conf_file
699     or a forced default file
700   */
701   if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+
702 			       (args.elements + *argc + 1 + args_sep) *sizeof(char*))))
703   {
704     delete_dynamic(&args);
705     goto err;
706   }
707   res= (char**) (ptr+sizeof(alloc));
708 
709   /* copy name + found arguments + command line arguments to new array */
710   res[0]= argv[0][0];  /* Name MUST be set, even by embedded library */
711   memcpy((uchar*) (res+1), args.buffer, args.elements*sizeof(char*));
712   /* Skip --defaults-xxx options */
713   (*argc)-= args_used;
714   (*argv)+= args_used;
715 
716   /*
717     Check if we wan't to see the new argument list
718     This options must always be the last of the default options
719   */
720   if (*argc >= 2 && !strcmp(argv[0][1],"--print-defaults"))
721   {
722     found_print_defaults=1;
723     --*argc; ++*argv;				/* skip argument */
724   }
725 
726   if (my_getopt_use_args_separator)
727   {
728     /* set arguments separator for arguments from config file and
729        command line */
730     set_args_separator(&res[args.elements+1]);
731   }
732 
733   if (*argc)
734     memcpy((uchar*) (res+1+args.elements+args_sep), (char*) ((*argv)+1),
735 	   (*argc-1)*sizeof(char*));
736   res[args.elements+ *argc+args_sep]=0;                /* last null */
737 
738   (*argc)+=args.elements+args_sep;
739   *argv= (char**) res;
740   *(MEM_ROOT*) ptr= alloc;			/* Save alloc root for free */
741   delete_dynamic(&args);
742 
743   if (default_directories)
744     *default_directories= dirs;
745 
746   if (found_no_defaults)
747     DBUG_RETURN(0);
748 
749   if (found_print_defaults)
750   {
751     int i;
752     printf("%s would have been started with the following arguments:\n",
753 	   **argv);
754     for (i=1 ; i < *argc ; i++)
755       if (!my_getopt_is_args_separator((*argv)[i])) /* skip arguments separator */
756         printf("%s ", (*argv)[i]);
757     puts("");
758     exit(0);
759   }
760 
761   DBUG_RETURN(0);
762 
763  err:
764   fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
765   exit(1);
766   DBUG_RETURN(0); /* Keep compiler happy */
767 }
768 
769 
free_defaults(char ** argv)770 void free_defaults(char **argv)
771 {
772   MEM_ROOT ptr;
773   memcpy(&ptr, ((char *) argv) - sizeof(ptr), sizeof(ptr));
774   free_root(&ptr,MYF(0));
775 }
776 
777 
search_default_file(Process_option_func opt_handler,void * handler_ctx,const char * dir,const char * config_file,my_bool is_login_file)778 static int search_default_file(Process_option_func opt_handler,
779                                void *handler_ctx,
780 			       const char *dir,
781                                const char *config_file,
782                                my_bool is_login_file)
783 {
784   char **ext;
785   const char *empty_list[]= { "", 0 };
786   my_bool have_ext= fn_ext(config_file)[0] != 0;
787   const char **exts_to_use= have_ext ? empty_list : f_extensions;
788 
789   for (ext= (char**) exts_to_use; *ext; ext++)
790   {
791     int error;
792     if ((error= search_default_file_with_ext(opt_handler, handler_ctx,
793                                              dir, *ext,
794                                              config_file, 0, is_login_file)) < 0)
795       return error;
796   }
797   return 0;
798 }
799 
800 
801 /*
802   Skip over keyword and get argument after keyword
803 
804   SYNOPSIS
805    get_argument()
806    keyword		Include directive keyword
807    kwlen		Length of keyword
808    ptr			Pointer to the keword in the line under process
809    line			line number
810 
811   RETURN
812    0	error
813    #	Returns pointer to the argument after the keyword.
814 */
815 
get_argument(const char * keyword,size_t kwlen,char * ptr,char * name,uint line)816 static char *get_argument(const char *keyword, size_t kwlen,
817                           char *ptr, char *name, uint line)
818 {
819   char *end;
820 
821   /* Skip over "include / includedir keyword" and following whitespace */
822 
823   for (ptr+= kwlen - 1;
824        my_isspace(&my_charset_latin1, ptr[0]);
825        ptr++)
826   {}
827 
828   /*
829     Trim trailing whitespace from directory name
830     The -1 below is for the newline added by fgets()
831     Note that my_isspace() is true for \r and \n
832   */
833   for (end= ptr + strlen(ptr) - 1;
834        my_isspace(&my_charset_latin1, *(end - 1));
835        end--)
836   {}
837   end[0]= 0;                                    /* Cut off end space */
838 
839   /* Print error msg if there is nothing after !include* directive */
840   if (end <= ptr)
841   {
842     fprintf(stderr,
843 	    "error: Wrong '!%s' directive in config file: %s at line %d\n",
844 	    keyword, name, line);
845     return 0;
846   }
847   return ptr;
848 }
849 
850 
851 /*
852   Open a configuration file (if exists) and read given options from it
853 
854   SYNOPSIS
855     search_default_file_with_ext()
856     opt_handler                 Option handler function. It is used to process
857                                 every separate option.
858     handler_ctx                 Pointer to the structure to store actual
859                                 parameters of the function.
860     dir				directory to read
861     ext				Extension for configuration file
862     config_file                 Name of configuration file
863     group			groups to read
864     recursion_level             the level of recursion, got while processing
865                                 "!include" or "!includedir"
866     is_login_file               TRUE, when login file is being processed.
867 
868   RETURN
869     0   Success
870     -1	Fatal error, abort
871      1	File not found (Warning)
872 */
873 
search_default_file_with_ext(Process_option_func opt_handler,void * handler_ctx,const char * dir,const char * ext,const char * config_file,int recursion_level,my_bool is_login_file)874 static int search_default_file_with_ext(Process_option_func opt_handler,
875                                         void *handler_ctx,
876                                         const char *dir,
877                                         const char *ext,
878                                         const char *config_file,
879                                         int recursion_level,
880                                         my_bool is_login_file)
881 {
882   char name[FN_REFLEN + 10], buff[4096], curr_gr[4096], *ptr, *end, **tmp_ext;
883   char *value, option[4096+2], tmp[FN_REFLEN];
884   static const char includedir_keyword[]= "includedir";
885   static const char include_keyword[]= "include";
886   const int max_recursion_level= 10;
887   MYSQL_FILE *fp;
888   uint line=0;
889   my_bool found_group=0;
890   uint i, rc;
891   MY_DIR *search_dir;
892   FILEINFO *search_file;
893 
894   if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3)
895     return 0;					/* Ignore wrong paths */
896   if (dir)
897   {
898     end=convert_dirname(name, dir, NullS);
899     if (dir[0] == FN_HOMELIB)		/* Add . to filenames in home */
900       *end++='.';
901     strxmov(end,config_file,ext,NullS);
902   }
903   else
904   {
905     strmov(name,config_file);
906   }
907   fn_format(name,name,"","",4);
908 
909   if ((rc= check_file_permissions(name, is_login_file)) < 2)
910     return (int) rc;
911 
912   if (is_login_file)
913   {
914     if ( !(fp = mysql_file_fopen(key_file_cnf, name, (O_RDONLY | O_BINARY),
915                                  MYF(0))))
916       return 1;                                 /* Ignore wrong files. */
917   }
918   else
919   {
920     if ( !(fp = mysql_file_fopen(key_file_cnf, name, O_RDONLY, MYF(0))))
921       return 1;                                 /* Ignore wrong files */
922   }
923 
924   while (mysql_file_getline(buff, sizeof(buff) - 1, fp, is_login_file))
925   {
926     line++;
927     /* Ignore comment and empty lines */
928     for (ptr= buff; my_isspace(&my_charset_latin1, *ptr); ptr++)
929     {}
930 
931     if (*ptr == '#' || *ptr == ';' || !*ptr)
932       continue;
933 
934     /* Configuration File Directives */
935     if (*ptr == '!')
936     {
937       if (recursion_level >= max_recursion_level)
938       {
939         for (end= ptr + strlen(ptr) - 1;
940              my_isspace(&my_charset_latin1, *(end - 1));
941              end--)
942         {}
943         end[0]= 0;
944         fprintf(stderr,
945                 "Warning: skipping '%s' directive as maximum include"
946                 "recursion level was reached in file %s at line %d\n",
947                 ptr, name, line);
948         continue;
949       }
950 
951       /* skip over `!' and following whitespace */
952       for (++ptr; my_isspace(&my_charset_latin1, ptr[0]); ptr++)
953       {}
954 
955       if ((!strncmp(ptr, includedir_keyword,
956                     sizeof(includedir_keyword) - 1)) &&
957           my_isspace(&my_charset_latin1, ptr[sizeof(includedir_keyword) - 1]))
958       {
959 	if (!(ptr= get_argument(includedir_keyword,
960                                 sizeof(includedir_keyword),
961                                 ptr, name, line)))
962 	  goto err;
963 
964         if (!(search_dir= my_dir(ptr, MYF(MY_WME))))
965           goto err;
966 
967         for (i= 0; i < (uint) search_dir->number_off_files; i++)
968         {
969           search_file= search_dir->dir_entry + i;
970           ext= fn_ext(search_file->name);
971 
972           /* check extension */
973           for (tmp_ext= (char**) f_extensions; *tmp_ext; tmp_ext++)
974           {
975             if (!strcmp(ext, *tmp_ext))
976               break;
977           }
978 
979           if (*tmp_ext)
980           {
981             fn_format(tmp, search_file->name, ptr, "",
982                       MY_UNPACK_FILENAME | MY_SAFE_PATH);
983 
984             search_default_file_with_ext(opt_handler, handler_ctx, "", "", tmp,
985                                          recursion_level + 1, is_login_file);
986           }
987         }
988 
989         my_dirend(search_dir);
990       }
991       else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) &&
992                my_isspace(&my_charset_latin1, ptr[sizeof(include_keyword)-1]))
993       {
994 	if (!(ptr= get_argument(include_keyword,
995                                 sizeof(include_keyword), ptr,
996                                 name, line)))
997 	  goto err;
998 
999         search_default_file_with_ext(opt_handler, handler_ctx, "", "", ptr,
1000                                      recursion_level + 1, is_login_file);
1001       }
1002 
1003       continue;
1004     }
1005 
1006     if (*ptr == '[')				/* Group name */
1007     {
1008       found_group=1;
1009       if (!(end=(char *) strchr(++ptr,']')))
1010       {
1011 	fprintf(stderr,
1012 		"error: Wrong group definition in config file: %s at line %d\n",
1013 		name,line);
1014 	goto err;
1015       }
1016       /* Remove end space */
1017       for ( ; my_isspace(&my_charset_latin1, end[-1]); end --)
1018       {}
1019 
1020       end[0]=0;
1021 
1022       strmake(curr_gr, ptr, MY_MIN((size_t) (end-ptr)+1, sizeof(curr_gr)-1));
1023 
1024       /* signal that a new group is found */
1025       opt_handler(handler_ctx, curr_gr, NULL);
1026 
1027       continue;
1028     }
1029     if (!found_group)
1030     {
1031       fprintf(stderr,
1032 	      "error: Found option without preceding group in config file: %s at line: %d\n",
1033 	      name,line);
1034       goto err;
1035     }
1036 
1037 
1038     end= remove_end_comment(ptr);
1039     if ((value= strchr(ptr, '=')))
1040       end= value;				/* Option without argument */
1041     for ( ; my_isspace(&my_charset_latin1, end[-1]) ; end--)
1042     {}
1043 
1044     if (!value)
1045     {
1046       strmake(strmov(option,"--"),ptr, (size_t) (end-ptr));
1047       if (opt_handler(handler_ctx, curr_gr, option))
1048         goto err;
1049     }
1050     else
1051     {
1052       /* Remove pre- and end space */
1053       char *value_end;
1054       for (value++ ; my_isspace(&my_charset_latin1, *value); value ++)
1055       {}
1056 
1057       value_end=strend(value);
1058       /*
1059 	We don't have to test for value_end >= value as we know there is
1060 	an '=' before
1061       */
1062       for ( ; my_isspace(&my_charset_latin1, value_end[-1]); value_end --)
1063       {}
1064 
1065       if (value_end < value)			/* Empty string */
1066 	value_end=value;
1067 
1068       /* remove quotes around argument */
1069       if ((*value == '\"' || *value == '\'') && /* First char is quote */
1070           (value + 1 < value_end ) && /* String is longer than 1 */
1071           *value == value_end[-1] ) /* First char is equal to last char */
1072       {
1073 	value++;
1074 	value_end--;
1075       }
1076       ptr=strnmov(strmov(option,"--"),ptr,(size_t) (end-ptr));
1077       *ptr++= '=';
1078 
1079       for ( ; value != value_end; value++)
1080       {
1081 	if (*value == '\\' && value != value_end-1)
1082 	{
1083 	  switch(*++value) {
1084 	  case 'n':
1085 	    *ptr++='\n';
1086 	    break;
1087 	  case 't':
1088 	    *ptr++= '\t';
1089 	    break;
1090 	  case 'r':
1091 	    *ptr++ = '\r';
1092 	    break;
1093 	  case 'b':
1094 	    *ptr++ = '\b';
1095 	    break;
1096 	  case 's':
1097 	    *ptr++= ' ';			/* space */
1098 	    break;
1099 	  case '\"':
1100 	    *ptr++= '\"';
1101 	    break;
1102 	  case '\'':
1103 	    *ptr++= '\'';
1104 	    break;
1105 	  case '\\':
1106 	    *ptr++= '\\';
1107 	    break;
1108 	  default:				/* Unknown; Keep '\' */
1109 	    *ptr++= '\\';
1110 	    *ptr++= *value;
1111 	    break;
1112 	  }
1113 	}
1114 	else
1115 	  *ptr++= *value;
1116       }
1117       *ptr=0;
1118       if (opt_handler(handler_ctx, curr_gr, option))
1119         goto err;
1120     }
1121   }
1122   mysql_file_fclose(fp, MYF(0));
1123   return(0);
1124 
1125  err:
1126   mysql_file_fclose(fp, MYF(0));
1127   return -1;					/* Fatal error */
1128 }
1129 
1130 
remove_end_comment(char * ptr)1131 static char *remove_end_comment(char *ptr)
1132 {
1133   char quote= 0;	/* we are inside quote marks */
1134   char escape= 0;	/* symbol is protected by escape chagacter */
1135 
1136   for (; *ptr; ptr++)
1137   {
1138     if ((*ptr == '\'' || *ptr == '\"') && !escape)
1139     {
1140       if (!quote)
1141 	quote= *ptr;
1142       else if (quote == *ptr)
1143 	quote= 0;
1144     }
1145     /* We are not inside a string */
1146     if (!quote && *ptr == '#')
1147     {
1148       *ptr= 0;
1149       return ptr;
1150     }
1151     escape= (quote && *ptr == '\\' && !escape);
1152   }
1153   return ptr;
1154 }
1155 
1156 
1157 /**
1158   Read one line from the specified file. In case
1159   of scrambled login file, the line read is first
1160   decrypted and then returned.
1161 
1162   @param str           [out]  Buffer to store the read text.
1163   @param size          [in]   At max, size-1 bytes to be read.
1164   @param file          [in]   Source file.
1165   @param is_login_file [in]   TRUE, when login file is being processed.
1166 
1167   @return 1               Success
1168           0               Error
1169 */
1170 
mysql_file_getline(char * str,int size,MYSQL_FILE * file,my_bool is_login_file)1171 static my_bool mysql_file_getline(char *str, int size, MYSQL_FILE *file,
1172                                   my_bool is_login_file)
1173 {
1174   uchar cipher[4096], len_buf[MAX_CIPHER_STORE_LEN];
1175   static unsigned char my_key[LOGIN_KEY_LEN];
1176   int length= 0, cipher_len= 0;
1177 
1178   if (is_login_file)
1179   {
1180     if (mysql_file_ftell(file, MYF(MY_WME)) == 0)
1181     {
1182       /* Move past unused bytes. */
1183       mysql_file_fseek(file, 4, SEEK_SET, MYF(MY_WME));
1184       if (mysql_file_fread(file, my_key, LOGIN_KEY_LEN,
1185                            MYF(MY_WME)) != LOGIN_KEY_LEN)
1186         return 0;
1187     }
1188 
1189     if (mysql_file_fread(file, len_buf, MAX_CIPHER_STORE_LEN,
1190                          MYF(MY_WME)) == MAX_CIPHER_STORE_LEN)
1191     {
1192       cipher_len= sint4korr(len_buf);
1193       if (cipher_len > size)
1194         return 0;
1195     }
1196     else
1197       return 0;
1198 
1199     mysql_file_fread(file, cipher, cipher_len, MYF(MY_WME));
1200     if ((length= my_aes_decrypt(cipher, cipher_len, (unsigned char *) str,
1201                                 my_key, LOGIN_KEY_LEN, my_aes_128_ecb, NULL)) < 0)
1202     {
1203       /* Attempt to decrypt failed. */
1204       return 0;
1205     }
1206     str[length]= 0;
1207     return 1;
1208   }
1209   else
1210   {
1211     if (mysql_file_fgets(str, size, file))
1212       return 1;
1213     else
1214       return 0;
1215   }
1216 }
1217 
1218 
my_print_default_files(const char * conf_file)1219 void my_print_default_files(const char *conf_file)
1220 {
1221   const char *empty_list[]= { "", 0 };
1222   my_bool have_ext= fn_ext(conf_file)[0] != 0;
1223   const char **exts_to_use= have_ext ? empty_list : f_extensions;
1224   char name[FN_REFLEN], **ext;
1225 
1226   puts("\nDefault options are read from the following files in the given order:");
1227 
1228   if (dirname_length(conf_file))
1229     fputs(conf_file,stdout);
1230   else
1231   {
1232     const char **dirs;
1233     MEM_ROOT alloc;
1234     init_alloc_root(&alloc,512,0);
1235 
1236     if ((dirs= init_default_directories(&alloc)) == NULL)
1237     {
1238       fputs("Internal error initializing default directories list", stdout);
1239     }
1240     else
1241     {
1242       for ( ; *dirs; dirs++)
1243       {
1244         for (ext= (char**) exts_to_use; *ext; ext++)
1245         {
1246           const char *pos;
1247           char *end;
1248           if (**dirs)
1249             pos= *dirs;
1250           else if (my_defaults_extra_file)
1251             pos= my_defaults_extra_file;
1252           else
1253             continue;
1254           end= convert_dirname(name, pos, NullS);
1255           if (name[0] == FN_HOMELIB)	/* Add . to filenames in home */
1256             *end++= '.';
1257 
1258           if (my_defaults_extra_file == pos)
1259             end[(strlen(end)-1)] = ' ';
1260           else
1261             strxmov(end, conf_file, *ext , " ",  NullS);
1262           fputs(name, stdout);
1263         }
1264       }
1265     }
1266 
1267     free_root(&alloc, MYF(0));
1268   }
1269   puts("");
1270 }
1271 
print_defaults(const char * conf_file,const char ** groups)1272 void print_defaults(const char *conf_file, const char **groups)
1273 {
1274   const char **groups_save= groups;
1275   my_print_default_files(conf_file);
1276 
1277   fputs("The following groups are read:",stdout);
1278   for ( ; *groups ; groups++)
1279   {
1280     fputc(' ',stdout);
1281     fputs(*groups,stdout);
1282   }
1283 
1284   if (my_defaults_group_suffix)
1285   {
1286     groups= groups_save;
1287     for ( ; *groups ; groups++)
1288     {
1289       fputc(' ',stdout);
1290       fputs(*groups,stdout);
1291       fputs(my_defaults_group_suffix,stdout);
1292     }
1293   }
1294   puts("\nThe following options may be given as the first argument:\n\
1295 --print-defaults        Print the program argument list and exit.\n\
1296 --no-defaults           Don't read default options from any option file,\n\
1297                         except for login file.\n\
1298 --defaults-file=#       Only read default options from the given file #.\n\
1299 --defaults-extra-file=# Read this file after the global files are read.\n\
1300 --defaults-group-suffix=#\n\
1301                         Also read groups with concat(group, suffix)\n\
1302 --login-path=#          Read this path from the login file.");
1303 }
1304 
1305 
add_directory(MEM_ROOT * alloc,const char * dir,const char ** dirs)1306 static int add_directory(MEM_ROOT *alloc, const char *dir, const char **dirs)
1307 {
1308   char buf[FN_REFLEN];
1309   size_t len;
1310   char *p;
1311   my_bool err MY_ATTRIBUTE((unused));
1312 
1313   len= normalize_dirname(buf, dir);
1314   if (!(p= strmake_root(alloc, buf, len)))
1315     return 1;  /* Failure */
1316   /* Should never fail if DEFAULT_DIRS_SIZE is correct size */
1317   err= array_append_string_unique(p, dirs, DEFAULT_DIRS_SIZE);
1318   DBUG_ASSERT(err == FALSE);
1319 
1320   return 0;
1321 }
1322 
1323 
1324 #ifdef __WIN__
1325 /*
1326   This wrapper for GetSystemWindowsDirectory() will dynamically bind to the
1327   function if it is available, emulate it on NT4 Terminal Server by stripping
1328   the \SYSTEM32 from the end of the results of GetSystemDirectory(), or just
1329   return GetSystemDirectory().
1330  */
1331 
1332 typedef UINT (WINAPI *GET_SYSTEM_WINDOWS_DIRECTORY)(LPSTR, UINT);
1333 
my_get_system_windows_directory(char * buffer,size_t size)1334 static size_t my_get_system_windows_directory(char *buffer, size_t size)
1335 {
1336   size_t count;
1337   GET_SYSTEM_WINDOWS_DIRECTORY
1338     func_ptr= (GET_SYSTEM_WINDOWS_DIRECTORY)
1339               GetProcAddress(GetModuleHandle("kernel32.dll"),
1340                                              "GetSystemWindowsDirectoryA");
1341 
1342   if (func_ptr)
1343     return func_ptr(buffer, (uint) size);
1344 
1345   /*
1346     Windows NT 4.0 Terminal Server Edition:
1347     To retrieve the shared Windows directory, call GetSystemDirectory and
1348     trim the "System32" element from the end of the returned path.
1349   */
1350   count= GetSystemDirectory(buffer, (uint) size);
1351   if (count > 8 && stricmp(buffer+(count-8), "\\System32") == 0)
1352   {
1353     count-= 8;
1354     buffer[count] = '\0';
1355   }
1356   return count;
1357 }
1358 
1359 
my_get_module_parent(char * buf,size_t size)1360 static const char *my_get_module_parent(char *buf, size_t size)
1361 {
1362   char *last= NULL;
1363   char *end;
1364   if (!GetModuleFileName(NULL, buf, (DWORD) size))
1365     return NULL;
1366   end= strend(buf);
1367 
1368   /*
1369     Look for the second-to-last \ in the filename, but hang on
1370     to a pointer after the last \ in case we're in the root of
1371     a drive.
1372   */
1373   for ( ; end > buf; end--)
1374   {
1375     if (*end == FN_LIBCHAR)
1376     {
1377       if (last)
1378       {
1379         /* Keep the last '\' as this works both with D:\ and a directory */
1380         end[1]= 0;
1381         break;
1382       }
1383       last= end;
1384     }
1385   }
1386 
1387   return buf;
1388 }
1389 #endif /* __WIN__ */
1390 
1391 
init_default_directories(MEM_ROOT * alloc)1392 static const char **init_default_directories(MEM_ROOT *alloc)
1393 {
1394   const char **dirs;
1395   char *env;
1396   int errors= 0;
1397 
1398   dirs= (const char **)alloc_root(alloc, DEFAULT_DIRS_SIZE * sizeof(char *));
1399   if (dirs == NULL)
1400     return NULL;
1401   memset(dirs, 0, DEFAULT_DIRS_SIZE * sizeof(char *));
1402 
1403 #ifdef __WIN__
1404 
1405   {
1406     char fname_buffer[FN_REFLEN];
1407     if (my_get_system_windows_directory(fname_buffer, sizeof(fname_buffer)))
1408       errors += add_directory(alloc, fname_buffer, dirs);
1409 
1410     if (GetWindowsDirectory(fname_buffer, sizeof(fname_buffer)))
1411       errors += add_directory(alloc, fname_buffer, dirs);
1412 
1413     errors += add_directory(alloc, "C:/", dirs);
1414 
1415     if (my_get_module_parent(fname_buffer, sizeof(fname_buffer)) != NULL)
1416       errors += add_directory(alloc, fname_buffer, dirs);
1417   }
1418 
1419 #else
1420 
1421   errors += add_directory(alloc, "/etc/", dirs);
1422   errors += add_directory(alloc, "/etc/mysql/", dirs);
1423 
1424 #if defined(DEFAULT_SYSCONFDIR)
1425   if (DEFAULT_SYSCONFDIR[0])
1426   {
1427     errors += add_directory(alloc, DEFAULT_SYSCONFDIR, dirs);
1428     errors += add_directory(alloc, DEFAULT_SYSCONFDIR "/mysql", dirs);
1429   }
1430 #endif /* DEFAULT_SYSCONFDIR */
1431 
1432 #endif
1433 
1434   if ((env= getenv("MYSQL_HOME")))
1435     errors += add_directory(alloc, env, dirs);
1436 
1437   /* Placeholder for --defaults-extra-file=<path> */
1438   errors += add_directory(alloc, "", dirs);
1439 
1440 #if !defined(__WIN__)
1441   errors += add_directory(alloc, "~/", dirs);
1442 #endif
1443 
1444   return (errors > 0 ? NULL : dirs);
1445 }
1446 
1447 /**
1448   Place the login file name in the specified buffer.
1449 
1450   @param file_name     [out]  Buffer to hold login file name
1451   @param file_name_size [in]  Length of the buffer
1452 
1453   @return 1 - Success
1454           0 - Failure
1455 */
1456 
my_default_get_login_file(char * file_name,size_t file_name_size)1457 int my_default_get_login_file(char *file_name, size_t file_name_size)
1458 {
1459   size_t rc;
1460 
1461   if (getenv("MYSQL_TEST_LOGIN_FILE"))
1462     rc= my_snprintf(file_name, file_name_size, "%s",
1463                     getenv("MYSQL_TEST_LOGIN_FILE"));
1464 #ifdef _WIN32
1465   else if (getenv("APPDATA"))
1466     rc= my_snprintf(file_name, file_name_size, "%s\\MySQL\\.mylogin.cnf",
1467                     getenv("APPDATA"));
1468 #else
1469   else if (getenv("HOME"))
1470     rc= my_snprintf(file_name, file_name_size, "%s/.mylogin.cnf",
1471                     getenv("HOME"));
1472 #endif
1473   else
1474   {
1475     memset(file_name, 0, file_name_size);
1476     return 0;
1477   }
1478   /* Anything <= 0 will be treated as error. */
1479   if (rc <= 0)
1480     return 0;
1481 
1482   return 1;
1483 }
1484 
1485 /**
1486   Check file permissions of the option file.
1487 
1488   @param file_name     [in]   Name of the option file.
1489   @param is_login_file [in]   TRUE, when login file is being processed.
1490 
1491   @return  0 - Non-allowable file permissions.
1492            1 - Failed to stat.
1493            2 - Success.
1494 */
check_file_permissions(const char * file_name,my_bool is_login_file)1495 int check_file_permissions(const char *file_name, my_bool is_login_file)
1496 {
1497 #if !defined(__WIN__)
1498   MY_STAT stat_info;
1499 
1500   if (!my_stat(file_name,&stat_info,MYF(0)))
1501     return 0;
1502   /*
1503     Ignore .mylogin.cnf file if not exclusively readable/writable
1504     by current user.
1505   */
1506   if (is_login_file && (stat_info.st_mode & (S_IXUSR | S_IRWXG | S_IRWXO))
1507       && (stat_info.st_mode & S_IFMT) == S_IFREG)
1508   {
1509     fprintf(stderr, "Warning: %s should be readable/writable only by "
1510             "current user.\n", file_name);
1511     return 0;
1512   }
1513   /*
1514     Ignore world-writable regular files.
1515     This is mainly done to protect us to not read a file created by
1516     the mysqld server, but the check is still valid in most context.
1517   */
1518   else if ((stat_info.st_mode & S_IWOTH) &&
1519            (stat_info.st_mode & S_IFMT) == S_IFREG)
1520 
1521   {
1522     fprintf(stderr, "Warning: World-writable config file '%s' is ignored\n",
1523             file_name);
1524     return 0;
1525   }
1526 #endif
1527   return 2;                                     /* Success */
1528 }
1529 
1530