File Coverage

blib/lib/Advanced/Config/Reader.pm
Criterion Covered Total %
statement 757 828 91.4
branch 357 450 79.3
condition 137 177 77.4
subroutine 30 31 96.7
pod 14 14 100.0
total 1295 1500 86.3


line stmt bran cond sub pod time code
1             ###
2             ### Copyright (c) 2007 - 2026 Curtis Leach. All rights reserved.
3             ###
4             ### Module: Advanced::Config::Reader
5              
6             =head1 NAME
7              
8             Advanced::Config::Reader - Reader manager for L.
9              
10             =head1 SYNOPSIS
11              
12             use Advanced::Config::Reader;
13             or
14             require Advanced::Config::Reader;
15              
16             =head1 DESCRIPTION
17              
18             F is a helper module to L. So it
19             should be very rare to directly call any methods defined by this module.
20              
21             This module manages reading the requested config file into memory and parsing
22             it for use by L.
23              
24             Each config file is highly customizable. Where you are allowed to alter the
25             comment char from B<#> to anything you like, such as B<;;>. The same is true
26             for things like the assignment operator (B<=>), and many other character
27             sequences with special meaning to this module.
28              
29             So to avoid confusion, when I talk about a feature, I'll talk about it's default
30             appearance and let it be safely assumed that the same will hold true if you've
31             overridden it's default character sequence with something else. Such as when
32             discussing comments as 'B<#>', even though you could have overridden it as
33             'B<;*;>'. See L for a list of symbols you can
34             overrides.
35              
36             You are also allowed to surround your values with balanced quotes or leave them
37             off entirely. The only time you must surround your value with quotes is when
38             you want to preserve leading or trailing spaces in your value. Without balanced
39             quotes these spaces are trimmed off. Also if you need a comment symbol in your
40             tag's value, the entire value must be surrounded by quotes! Finally, unbalanced
41             quotes can behave very strangly and are not stripped off.
42              
43             So in general white space in your config file is basically ignored unless it's
44             surrounded by printable chars or quotes.
45              
46             Sorry you can't use a comment symbol as part of your tag's name.
47              
48             See L for some sample config files. You may also
49             find a lot of example config files in the package you downloaded from CPAN to
50             install this module from under I.
51              
52             =head1 FUNCTIONS
53              
54             =over 4
55              
56             =cut
57              
58             package Advanced::Config::Reader;
59              
60 26     26   479776 use strict;
  26         50  
  26         1017  
61 26     26   119 use warnings;
  26         52  
  26         1678  
62              
63 26     26   163 use vars qw( @ISA @EXPORT @EXPORT_OK $VERSION );
  26         47  
  26         1697  
64 26     26   171 use Exporter;
  26         49  
  26         1101  
65              
66 26     26   2574 use Advanced::Config::Options;
  26         50  
  26         2905  
67 26     26   3578 use Advanced::Config;
  26         73  
  26         1452  
68              
69 26     26   194 use Fred::Fish::DBUG 2.09 qw / on_if_set ADVANCED_CONFIG_FISH /;
  26         647  
  26         221  
70              
71 26     26   8835 use File::Basename;
  26         80  
  26         6326  
72              
73             $VERSION = "1.14";
74             @ISA = qw( Exporter );
75              
76             @EXPORT = qw( read_config source_file make_new_section parse_line
77             expand_variables apply_modifier parse_for_variables
78             format_section_line format_tag_value_line format_encrypt_cmt
79             encrypt_config_file_details decrypt_config_file_details );
80              
81             @EXPORT_OK = qw( );
82              
83             my $skip_warns_due_to_make_test;
84             my %global_sections;
85             my $gUserName;
86              
87             # ==============================================================
88             # NOTE: It is extreemly dangerous to reference Advanced::Config
89             # internals in this code. Avoid where possible!!!
90             # Ask for copies from the module instead.
91             # ==============================================================
92             # Any other module initialization done here ...
93             # This block references initializations done in my other modules.
94             BEGIN
95             {
96 26     26   190 DBUG_ENTER_FUNC ();
97              
98             # What we call our default section ...
99 26         7870 $global_sections{DEFAULT} = Advanced::Config::Options::DEFAULT_SECTION_NAME;
100 26         86 $global_sections{OVERRIDE} = $global_sections{DEFAULT};
101              
102 26         121 $gUserName = Advanced::Config::Options::_get_user_id ();
103              
104             # Is the code being run via "make test" environment ...
105 26 0 33     5797 if ( $ENV{PERL_DL_NONLAZY} ||
      0        
106             $ENV{PERL_USE_UNSAFE_INC} ||
107             $ENV{HARNESS_ACTIVE} ) {
108 26         58 $skip_warns_due_to_make_test = 1;
109             }
110              
111 26         92 DBUG_VOID_RETURN ();
112             }
113              
114              
115             # ==============================================================
116             # No fish please ... (called way too often)
117             # This method is called in 2 ways:
118             # 1) By parse_line() to determine if ${ln} is a tag/value pair.
119             # 2) By everyone else to parse a known tag/value pair in ${ln}.
120             #
121             # ${ln} is in one of these 3 formats if it's a tag/value pair.
122             # tag = value
123             # export tag = value # Unix shell scripts
124             # set tag = value # Windows Batch files
125              
126             sub _split_assign
127             {
128 103717     103717   180881 my $rOpts = shift; # The read options ...
129 103717         186812 my $ln = shift; # The value to split ...
130 103717         175055 my $skip = shift; # Skip massaging the tag?
131              
132 103717         192141 my ( $tag, $value );
133 103717 100       317924 if ( is_assign_spaces ( $rOpts ) ) {
134 396         1651 ( $tag, $value ) = split ( " ", $ln, 2 );
135 396         777 $skip = 1; # This separator doesn't support the prefixes.
136             } else {
137 103321         267214 my $assign_str = convert_to_regexp_string ($rOpts->{assign}, 1);
138 103321         1202224 ( $tag, $value ) = split ( /\s*${assign_str}\s*/, $ln, 2 );
139             }
140              
141 103717         272299 my $export_prefix = "";
142              
143 103717 100       272934 unless ( $skip ) {
144             # Check if one of the export/set variable prefixes were used!
145 46783 100       240075 if ( $tag =~ m/^(export\s+)(\S.*)$/i ) {
    100          
146 2         10 $tag = $2; # Remove the leading "export" keyword ...
147 2         7 $export_prefix = $1;
148             } elsif ( $tag =~ m/^(set\s+)(\S.*)$/i ) {
149 2         10 $tag = $2; # Remove the leading "set" keyword ...
150 2         6 $export_prefix = $1;
151             }
152             }
153              
154             # Did we request case insensitive tags ... ?
155 103717 100 100     398996 my $ci_tag = ( $rOpts->{tag_case} && defined $tag ) ? lc ($tag) : $tag;
156              
157 103717         423312 return ( $ci_tag, $value, $export_prefix, $tag );
158             }
159              
160              
161             # ==============================================================
162              
163             =item $sts = read_config ( $file, $config )
164              
165             This method performs the reading and parsing of the given config file and puts
166             the results into the L object I<$config>. This object
167             provides the necessary parsing rules to use.
168              
169             If a line was too badly mangled to be parsed, it will be ignored and a warning
170             will be written to your screen.
171              
172             It returns B<1> on success and B<0> on failure.
173              
174             Please note that comments are just thrown away by this process and only
175             tag/value pairs remain afterwards. Everything else is just instructions to
176             the parser or how to group together these tag/value pairs.
177              
178             If it sees something like: export tag = value, it will export tag's value
179             to the %ENV hash for you just like it does in a Unix shell script!
180              
181             Additional modifiers can be found in the comments after a tag/value pair
182             as well.
183              
184             =cut
185              
186             # ==============================================================
187             sub read_config
188             {
189 185     185 1 826 DBUG_ENTER_FUNC ( @_ );
190 185         100996 my $file = shift; # The filename to read ...
191 185         494 my $cfg = shift; # The Advanced::Config object ...
192              
193 185         1242 my $opts = $cfg->get_cfg_settings (); # The Read Options ...
194              
195             # Locate the parent section of the config file.
196 185         48202 my $pcfg = $cfg->get_section ();
197              
198             # Using a variable so that we can be recursive in reading config files.
199 185         45842 my $READ_CONFIG;
200              
201 185         801 DBUG_PRINT ("INFO", "Opening the config file named: %s", $file);
202              
203 185 50       53677 unless ( open ($READ_CONFIG, "<", $file) ) {
204 0         0 return DBUG_RETURN ( croak_helper ($opts,
205             "Unable to open the config file.", 0) );
206             }
207              
208             # Misuse of this option makes the config file unreadable ...
209 185 100       1163 if ( $opts->{use_utf8} ) {
210 3         143 binmode ($READ_CONFIG, "encoding(UTF-8)");
211 3         409 $pcfg->_allow_utf8 (); # Tells get_date() that wide char languages are OK!
212             }
213              
214             # Some common RegExp strings ... Done here to avoid asking repeatably ...
215 185         1400 my $decrypt_str = convert_to_regexp_string ($opts->{decrypt_lbl});
216 185         45991 my $encrypt_str = convert_to_regexp_string ($opts->{encrypt_lbl});
217 185         44995 my $hide_str = convert_to_regexp_string ($opts->{hide_lbl});
218 185         45338 my $sect_str = convert_to_regexp_string ($opts->{source_file_section_lbl});
219              
220 185         45289 my $export_str = convert_to_regexp_string ($opts->{export_lbl});
221             my ($lb, $rb) = ( convert_to_regexp_string ($opts->{section_left}),
222 185         92193 convert_to_regexp_string ($opts->{section_right}) );
223 185         46608 my $assign_str = convert_to_regexp_string ($opts->{assign});
224 185         45266 my $src_str = convert_to_regexp_string ($opts->{source});
225             my ($lv, $rv) = ( convert_to_regexp_string ($opts->{variable_left}),
226 185         45696 convert_to_regexp_string ($opts->{variable_right}) );
227              
228             # The label separators used when searching for option labels in a comment ...
229 185         46476 my $lbl_sep = '[\s.,$!()-]';
230              
231             # Initialize to the default secion ...
232 185         930 my $section = make_new_section ( $cfg, "" );
233              
234 185         90964 my %hide_section;
235              
236 185         22156 while ( <$READ_CONFIG> ) {
237 41998         112202 chomp;
238 41998         87857 my $line = $_; # Save so can use in fish logging later on.
239              
240 41998         125183 my ($tv, $ln, $cmt, $lq, $rq) = parse_line ( $line, $opts );
241              
242 41998 100       8633498 if ( $ln eq "" ) {
243 7735         29419 DBUG_PRINT ("READ", "READ LINE: %s", $line);
244 7735         1699667 next; # Skip to the next line if only comments found.
245             }
246              
247             # Check for lines with no tag/value pairs in them ...
248 34263 100       103737 if ( ! $tv ) {
249 694         2718 DBUG_PRINT ("READ", "READ LINE: %s", $line);
250              
251             # EX: . ${file} --- Sourcing in ${file} ...
252 694 100       131833 if ( $ln =~ m/^${src_str}\s+(.+)$/i ) {
253 46         234 my $src = $1;
254 46         159 my $def_section = "";
255 46 100       1327 if ( $cmt =~ m/(^|${lbl_sep})${sect_str}(${lbl_sep}|$)/ ) {
256 17         55 $def_section = $section;
257             }
258 46         251 my $res = source_file ( $cfg, $def_section, $src, $file );
259 46 50       12796 return DBUG_RETURN (0) unless ( $res );
260 46         361 next;
261             }
262              
263             # EX: [ ${section} ] --- Starting a new section ...
264 648 100       12535 if ( $ln =~ m/^${lb}\s*(.+?)\s*${rb}$/ ) {
265 635         2960 $section = make_new_section ( $cfg, $1 );
266              
267 635         239332 $hide_section{$section} = 0; # Assume not sensitive ...
268              
269 635 100 66     9338 if ( $cmt =~ m/(^|${lbl_sep})${hide_str}(${lbl_sep}|$)/ ||
270             should_we_hide_sensitive_data ( $section ) ) {
271 8         2204 $hide_section{$section} = 1;
272             }
273 635         121320 next;
274             }
275              
276             # Don't know what the config file was thinking of ...
277             # Don't bother expanding any variables encountered.
278 13         56 DBUG_PRINT ("error", "");
279 13         1199 next;
280             }
281              
282             # ------------------------------------------------------------------
283             # If you get here, you know it's a tag/value pair to parse ...
284             # Don't forget that any comment can include processing instructions!
285             # ------------------------------------------------------------------
286              
287             # Go to the requested section ...
288 33569         155826 $cfg = $pcfg->get_section ( $section, 1 );
289              
290 33569         5655985 my ($tag, $value, $prefix, $t2) = _split_assign ( $opts, $ln );
291              
292             # Don't export individually if doing a batch export ...
293             # If the export option is used, invert the meaning ...
294 33569         74731 my $export_flag = 0; # Assume not exporting this tag to %ENV ...
295 33569 100       246251 if ( $prefix ) {
    50          
296 4 50       25 $export_flag = $opts->{export} ? 0 : 1;
297             } elsif ( $cmt =~ m/(^|${lbl_sep})${export_str}(${lbl_sep}|$)/ ) {
298 0 0       0 $export_flag = $opts->{export} ? 0 : 1;
299             }
300              
301             # Is the line info sensitive & should it be hidden/masked in fish ???
302 33569         70914 my $hide = 0;
303 33569 100 100     457170 if ( $hide_section{$section} ||
      100        
      100        
304             $cmt =~ m/(^|${lbl_sep})${encrypt_str}(${lbl_sep}|$)/ ||
305             $cmt =~ m/(^|${lbl_sep})${hide_str}(${lbl_sep}|$)/ ||
306             should_we_hide_sensitive_data ( $tag, 1 ) ) {
307 12789 100       41910 $hide = 1 unless ( $opts->{dbug_test_use_case_hide_override} );
308             }
309              
310 33569 100       221814 if ( $hide ) {
    100          
311             # Some random length so we can't assume the value from the mask used!
312 589         1167 my $mask = "*"x8;
313 589 50       2376 if ( $value eq "" ) {
314 0 0       0 if ( is_assign_spaces ( $opts ) ) {
315 0         0 $line =~ s/^(\s*\S+\s+)/${1}${mask} /;
316             } else {
317 0         0 $line =~ s/(\s*${assign_str})\s*/${1} ${mask} /;
318             }
319             } else {
320 589         1746 my $hide_value = convert_to_regexp_string ( $value, 1 );
321 589 100       1985 if ( is_assign_spaces ( $opts ) ) {
322 3         116 $line =~ s/^(\s*\S+\s+)${hide_value}/${1}${mask}/;
323             } else {
324 586         40516 $line =~ s/(\s*${assign_str}\s*)${hide_value}/${1}${mask}/;
325             }
326             }
327              
328             } elsif ( $cmt =~ m/(^|${lbl_sep})${decrypt_str}(${lbl_sep}|$)/ ) {
329             # Don't hide the line in fish, but hide it's value processing ...
330 6200 100       21588 $hide = 1 unless ( $opts->{dbug_test_use_case_hide_override} );
331             }
332              
333 33569         132179 DBUG_PRINT ("READ", "READ LINE: %s", $line);
334              
335             # Remove any balanced quotes ... (must do after hide)
336 33569 100       5286375 $value =~ s/^${lq}(.*)${rq}$/$1/ if ( $lq );
337              
338 33569 100       121301 if ( $tag =~ m/^(shft3+)$/i ) {
339 116         572 my $m = "You can't override special variable '${1}'."
340             . " Ignoring this line in the config file.\n";
341 116 50       473 if ( $skip_warns_due_to_make_test ) {
342 116         467 DBUG_PRINT ("WARN", $m);
343             } else {
344 0         0 warn $m;
345             }
346 116         28971 next;
347             }
348              
349             # Was the tag's value encryped?? Then we need to decrypt it ...
350 33453         65290 my $still_encrypted = 0;
351 33453 100       200184 if ( $cmt =~ m/(^|${lbl_sep})${decrypt_str}(${lbl_sep}|$)/ ) {
352 6224         19870 $value = _reverse_escape_sequences ( $value, $opts );
353              
354 6224 100       701499 if ( $opts->{disable_decryption} ) {
355 14         39 $still_encrypted = 1; # Doesn't get decrypted.
356             } else {
357 6210         19253 $value = decrypt_value ( $value, $t2, $opts, $file );
358             }
359             }
360              
361             # See if we can expand variables in $value ???
362 33453         675217 my $still_variables = 0;
363 33453 100       137212 if ( $opts->{disable_variables} ) {
    100          
364 208 100       1311 $still_variables = ( $value =~ m/${lv}.+${rv}/ ) ? 1 : 0;
365             } elsif ( ! $still_encrypted ) {
366 33231 100       127580 ($value, $hide) = expand_variables ( $cfg, $value, $file, $hide, ($lq ? 0 : 1) );
367 33231 100       6084230 if ( $hide == -1 ) {
368             # $still_encrypted = $still_variables = 1;
369 29         82 $still_variables = 1; # Variable(s) points to encrypted data.
370             }
371             }
372              
373             # Export one value to %ENV ... (once set, can't back it out again!)
374 33453 100       110180 $cfg->export_tag_value_to_ENV ( $tag, $value, $hide ) if ($export_flag);
375              
376             # Add to the current section in the Advanced::Config object ...
377 33453         181293 $cfg->_base_set ($tag, $value, $file, $hide, $still_encrypted, $still_variables);
378             } # End while reading the config file ...
379              
380 185         3091 close ( $READ_CONFIG );
381              
382 185         843 DBUG_RETURN (1);
383             }
384              
385              
386             # ==============================================================
387              
388             =item $boolean = source_file ($config, $def_sct, $new_file, $curr_file)
389              
390             This is a private method called by I to source in the requested
391             config file and merge the results into the current config file.
392              
393             If I<$def_sct> is given, it will be the name of the current section that the
394             sourced in file is to use for it's default unlabeled section. If the default
395             section name has been hard coded in the config file, this value overrides it.
396              
397             The I<$new_file> may contain variables and after they are expanded the
398             source callback function is called before I is called.
399             See L for rules on variable expansion.
400              
401             If I<$new_file> is a relative path, it's a relative path from the location
402             of I<$curr_file>, not the program's current directory!
403              
404             If a source callback was set up, it will call it here.
405              
406             This method will also handle the removal of decryption related options if new
407             ones weren't provided by the callback function. See Advanced::Config::Options
408             for more details.
409              
410             Returns B<1> if the new file successfully loaded. Else B<0> if something went
411             wrong during the load!
412              
413             =cut
414              
415             sub source_file
416             {
417 46     46 1 224 DBUG_ENTER_FUNC (@_);
418 46         27483 my $cfg = shift;
419 46         156 my $defaultSection = shift; # The new default section if not "".
420 46         111 my $new_file = shift; # May contain variables to expand ...
421 46         104 my $old_file = shift; # File we're currently parsing. (has abs path)
422              
423 46         317 my $rOpts = $cfg->get_cfg_settings (); # The Read Options ...
424              
425 46 100       13004 local $global_sections{OVERRIDE} = $defaultSection if ( $defaultSection );
426              
427 46         252 my $pcfg = $cfg->get_section (); # Back to the main/default section ...
428              
429 46         12766 my $file = $new_file = expand_variables ($pcfg, $new_file, undef, undef, 1);
430              
431             # Get the full name of the file we're sourcing in ...
432 46         15809 $file = $pcfg->_fix_path ( $file, dirname ( $old_file ) );
433              
434 46 50 33     14682 unless ( -f $file && -r _ ) {
435 0         0 my $msg = "No such file to source in or it's unreadable ( $file )";
436 0         0 return DBUG_RETURN ( croak_helper ( $rOpts, $msg, 0 ) );
437             }
438              
439 46 100       354 if ( $cfg->_recursion_check ( $file ) ) {
440 2         602 my $msg = "Recursion detected while sourcing in file ( $new_file )";
441 2 50       10 if ( $rOpts->{trap_recursion} ) {
442             # The request is a fatal error!
443 0         0 return DBUG_RETURN ( croak_helper ( $rOpts, $msg, 0 ) );
444             } else {
445 2         8 DBUG_PRINT ("RECURSION", $msg);
446 2         585 return DBUG_RETURN ( 1 ); # Just ignore the request ...
447             }
448             }
449              
450             # The returned callback option(s) will be applied to the current
451             # settings, not the default settings if not a compete set!
452 44         11531 my ($r_opts, $d_opts);
453 44 50 33     368 if ( exists $rOpts->{source_cb} && ref ( $rOpts->{source_cb} ) eq "CODE" ) {
454 44         305 ($r_opts, $d_opts) = $rOpts->{source_cb}->( $file, $rOpts->{source_cb_opts} );
455             }
456              
457 44 0 33     135473 if ( $rOpts->{inherit_pass_phase} && $rOpts->{pass_phrase} ) {
458 0         0 my %empty;
459 0 0       0 $r_opts = \%empty unless ( defined $r_opts );
460 0 0       0 $r_opts->{pass_phrase} = $rOpts->{pass_phrase} unless ( $r_opts->{pass_phrase} );
461             }
462              
463 44         335 my $res = $pcfg->_load_config_with_new_date_opts ( $file, $r_opts, $d_opts );
464              
465 44 50       11888 DBUG_RETURN ( (defined $res) ? 1 : 0 );
466             }
467              
468              
469             # ==============================================================
470              
471             =item $name = make_new_section ($config, $section)
472              
473             This is a private method called by I to create a new section
474             in the L object if a section of that name doesn't already
475             exist.
476              
477             The I<$section> name is allowed to contain variables to expand before the
478             string is used. But those variables must be defined in the I
section.
479              
480             Returns the name of the section found/created in lower case.
481              
482             =cut
483              
484             sub make_new_section
485             {
486 820     820 1 3600 DBUG_ENTER_FUNC (@_);
487 820         344932 my $config = shift;
488 820         3076 my $new_name = shift;
489              
490             # Check if overriding the default section with a new name ...
491 820 100 100     6407 if ( $new_name eq "" || $new_name eq $global_sections{DEFAULT} ) {
492 221 100       1198 if ( $global_sections{DEFAULT} ne $global_sections{OVERRIDE} ) {
493             DBUG_PRINT ("OVERRIDE", "Overriding section '%s' with section '%s'",
494 35         186 $new_name, $global_sections{OVERRIDE});
495 35         10405 $new_name = $global_sections{OVERRIDE};
496             }
497             }
498              
499 820         4540 my $pcfg = $config->get_section (); # Back to the main section ...
500              
501 820         170700 my $val = expand_variables ($pcfg, $new_name, undef, undef, 1);
502 820         180010 $new_name = lc ( $val );
503              
504             # Check if the section name is already in use ...
505 820         3902 my $old = $pcfg->get_section ( $new_name );
506 820 100       177197 if ( $old ) {
507 489         2564 return DBUG_RETURN ( $old->section_name() );
508             }
509              
510             # Create the new section now that we know it's name is unique ...
511 331         1818 my $scfg = $pcfg->create_section ( $new_name );
512              
513 331 50       128709 if ( $scfg ) {
514 331         1679 return DBUG_RETURN ( $scfg->section_name () );
515             }
516              
517             # Should never, ever happen ...
518 0         0 DBUG_PRINT ("WARN", "Failed to create the new section: %s.", $new_name);
519              
520 0         0 DBUG_RETURN (""); # This is the main/default section being returned.
521             }
522              
523              
524             # ==============================================================
525             # Allows a config file to run a random command when it's loaded into memory.
526             # Only allowed if explicity enabled & configured!
527             # Decided it's too dangerous to use, so never called outside of a POC example!
528             sub _execute_backquoted_cmd
529             {
530 0     0   0 my $rOpts = shift;
531 0         0 my $hide = shift;
532 0         0 my $tag = shift;
533 0         0 my $value = shift;
534              
535 0 0       0 return ( $value ) unless ( $rOpts->{enable_backquotes} );
536              
537             # Left & right backquotes ...
538             my ($lbq, $rbq) = ( convert_to_regexp_string ($rOpts->{backquote_left}, 1),
539 0         0 convert_to_regexp_string ($rOpts->{backquote_right}, 1) );
540              
541 0 0       0 unless ( $value =~ m/^${lbq}(.*)${rbq}$/ ) {
542 0         0 return ( $value ); # No balanced backquotes detected ...
543             }
544 0         0 my $cmd = $1; # The command to run ...
545              
546             # DBUG_MASK_NEXT_FUNC_CALL (3) if ( $hide ); # Never hide value (cmd to run)
547 0         0 DBUG_ENTER_FUNC ($rOpts, $hide, $tag, $value, @_);
548 0 0       0 DBUG_MASK (0) if ( $hide ); # OK to hide the results.
549              
550 0 0       0 if ( $cmd =~ m/[`]/ ) {
    0          
551 0         0 DBUG_PRINT ('INFO', 'Your command may not have backquotes (`) in it!');
552             } elsif ( $cmd =~ m/^\s*$/ ) {
553 0         0 DBUG_PRINT ('INFO', 'Your command must have a value!');
554              
555             } else {
556 0         0 die ("Someone tried to run cmd: $cmd\n");
557             # $value = `$cmd`;
558 0 0       0 $value = "" unless ( defined $value );
559 0         0 chomp ($value);
560             }
561              
562 0         0 DBUG_RETURN ($value);
563             }
564              
565              
566             # ==============================================================
567              
568             =item @ret[0..4] = parse_line ( $input, \%opts )
569              
570             This is a private method called by I to parse each line of the
571             config file as it's read in. It's main purpose is to strip off leading and
572             trailing spaces and any comments it might find on the input line. It also
573             tells if the I<$input> contains a tag/value pair.
574              
575             It returns 5 values: ($tv_flg, $line, $comment, $lQuote, $rQuote)
576              
577             B<$tv_flg> - True if I<$line> contains a tag/value pair in it, else false.
578              
579             B<$line> - The trimmed I<$input> line minus any comments.
580              
581             B<$comment> - The comment stripped out of the original input line minus the
582             leading comment symbol(s).
583              
584             B<$lQuote> & B - Only set if I<$tv_flg> is true and I<$lQuote> was
585             the 1st char of the value and I<$rQuote> was the last char of the tag's value.
586             If the value wasn't surrounded by balanced quotes, both return values will be
587             the empty string B<"">.
588              
589             If these quotes are returned, it expects the caller to remove them from the
590             tag's value. The returned values for these quote chars are suitable for use as
591             is in a RegExpr. The caller must do this in order to preserve potential
592             leading/trailing spaces.
593              
594             =cut
595              
596             sub parse_line
597             {
598 56814     56814 1 929340 DBUG_MASK_NEXT_FUNC_CALL (0); # Masks ${line}!
599 56814         2510586 DBUG_ENTER_FUNC ( @_ );
600 56814         24897009 my $line = shift;
601 56814 50       234554 my $opts = (ref ($_[0]) eq "HASH" ) ? $_[0] : {@_};
602              
603             # Mask the ${line} return value in fish ...
604             # Only gets unmasked in the test scripts: t/*.t.
605             # Always pause since by the time we detect if it should be
606             # hidden or not it's too late. We've already written it to fish!
607 56814 100       236177 unless ( $opts->{dbug_test_use_case_parse_override} ) {
608 20353         72882 DBUG_MASK ( 1 );
609 20353         752743 DBUG_PAUSE ();
610             }
611              
612             # Strip of leading & trailing spaces ...
613 56814         7307504 $line =~ s/^\s+//;
614 56814         256317 $line =~ s/\s+$//;
615              
616 56814         221390 my $default_quotes = using_default_quotes ( $opts );
617              
618 56814         8687102 my $comment = convert_to_regexp_string ($opts->{comment}, 1);
619              
620 56814         176302 my ($tag, $value) = _split_assign ( $opts, $line, 1 );
621              
622 56814         172271 my ($l_quote, $r_quote, $tv_pair_flag) = ("", "", 0);
623 56814         103027 my $var_line = $line;
624              
625 56814 100 100     457185 unless ( defined $tag && defined $value ) {
    100          
626 9632         20905 $tag = $value = undef; # It's not a tag/value pair ...
627              
628 0 50       0 } elsif ( $tag eq "" || $tag =~ m/${comment}/ ) {
629 187         513 $tag = $value = undef; # It's not a valid tag ...
630              
631             } else {
632             # It looks like a tag/value pair to me ...
633 46995         92219 $tv_pair_flag = 1;
634              
635 46995 50       154437 if ( $opts->{disable_quotes} ) {
    100          
636             ; # Don't do anything ...
637              
638             } elsif ( $default_quotes ) {
639 43353 100       170711 if ( $value =~ m/^(['"])/ ) {
640 26373         96502 $l_quote = $r_quote = $1; # A ' or ". (Never both)
641             }
642              
643             # User defined quotes ...
644             } else {
645 3642         14337 my $q = convert_to_regexp_string ($opts->{quote_left}, 1);
646 3642 100       27428 if ( $value =~ m/^(${q})/ ) {
647 692         1519 $l_quote = $q;
648 692         2248 $r_quote = convert_to_regexp_string ($opts->{quote_right}, 1);
649             }
650             }
651              
652 46995         91605 $var_line = $value;
653             }
654              
655             # Comment still in value, but still haven't proved any quotes are balanced.
656 56814         257696 DBUG_PRINT ("DEBUG", "Tag (%s), Value (%s), Proposed Left (%s), Right (%s)",
657             $tag, $value, $l_quote, $r_quote);
658              
659 56814         7613103 my $cmts = "";
660              
661             # Was the value in the tag/value pair starting with a left quote?
662 56814 100 100     273181 if ( $tv_pair_flag && $l_quote ne "" ) {
663 27065         62549 my ($q1, $val2, $q2);
664              
665             # Now check if they were balanced ...
666 27065 100       394906 if ( $value =~ m/^(${l_quote})(.*)(${r_quote})(\s*${comment}.*$)/ ) {
    100          
667 19083         135899 ($q1, $val2, $q2, $cmts) = ($1, $2, $3, $4); # Has a comment ...
668             } elsif ( $value =~ m/^(${l_quote})(.*)(${r_quote})\s*$/ ) {
669 7918         45133 ($q1, $val2, $q2, $cmts) = ($1, $2, $3, ""); # Has no comment ...
670             }
671              
672             # If balanced quotes were found ...
673 27065 100       78125 if ( $q1 ) {
674             # If the surrounding quotes don't have quotes inside them ...
675             # IE not malformed ...
676 27001 100 66     212758 unless ( $val2 =~ m/${l_quote}/ || $val2 =~ m/${r_quote}/ ) {
677 26997         93779 my $cmt2 = convert_to_regexp_string ($cmts);
678 26997         4108850 $cmts =~ s/^\s*${comment}\s*//; # Remove comment symbol ...
679 26997 100       282280 $line =~ s/${cmt2}$// if ($cmt2 ne "" ); # Remove the comments ...
680              
681 26997         104424 DBUG_PRINT ("LINE", "Balanced Quotes encountered for removal ...");
682 26997         3187013 return DBUG_RETURN ( $tv_pair_flag, $line, $cmts, $l_quote, $r_quote);
683             }
684             }
685             }
686              
687             # The Quotes weren't balanced, so they can no longer be removed from
688             # arround the value of what's returned!
689 29817         71452 $l_quote = $r_quote = "";
690              
691             # ----------------------------------------------------------------------
692             # If no comments in the line, just return the trimmed string ...
693             # Both tests are needed due to custom comment/assign strings!
694             # ----------------------------------------------------------------------
695 29817 100       181559 if ( $line !~ m/${comment}/ ) {
696 13142         42323 DBUG_PRINT ("LINE", "Simply no comments to worry about ...");
697 13142         1472078 return DBUG_RETURN ( $tv_pair_flag, $line, "", "", "" );
698             }
699              
700             # Handles case where a comment char embedded in the assignment string.
701 16675 100 100     96287 if ( $tv_pair_flag && $value !~ m/${comment}/ ) {
702 65         293 DBUG_PRINT ("LINE", "Simply no comments in the value to worry about ...");
703 65         5954 return DBUG_RETURN ( $tv_pair_flag, $line, "", "", "" );
704             }
705              
706             # ----------------------------------------------------------------------
707             # If not protected by balanced quotes, verify the comment symbol detected
708             # isn't actually a variable modifier. Variables are allowed in most places
709             # in the config file, not just in tag/value pairs.
710             # ----------------------------------------------------------------------
711              
712             # The left & right anchor points for variable substitution ...
713 16610         63107 my $lvar = convert_to_regexp_string ($opts->{variable_left}, 1);
714 16610         50575 my $rvar = convert_to_regexp_string ($opts->{variable_right}, 1);
715              
716             # Determine what value to use in variable substitutions that doesn't include
717             # a variable tag, or a comment tag, or a value in the $line.
718 16610         31604 my $has_no_cmt;
719 16610         60267 foreach ("A" .. "Z", "@") {
720 16610         42934 $has_no_cmt = ${_}x10;
721 16610 50 33     225814 last unless ( $has_no_cmt =~ m/${comment}/ ||
      33        
      33        
722             $has_no_cmt =~ m/${lvar}/ ||
723             $has_no_cmt =~ m/${rvar}/ ||
724             $line =~ m/${has_no_cmt}/ );
725             }
726 16610 50       52881 if ( $has_no_cmt eq "@"x10 ) {
727 0         0 warn ("May be having variable substitution issues in parse_line()!\n");
728             }
729              
730             # Strip out all the variables from the value ...
731             # Assumes processing variables from left to right ...
732             # Need to evaluate even if variables are disabled to parse correctly ...
733 16610         53978 my @parts = parse_for_variables ($var_line, 1, $opts);
734 16610         3396231 my $cmt_found = 0;
735 16610         31416 my $count_var = 0;
736 16610         32043 my @data;
737 16610         55488 while (defined $parts[0]) {
738 1667         3599 $cmt_found = $parts[3];
739 1667         3993 push (@data, $var_line);
740 1667 100       4981 last if ($cmt_found);
741 1452         3961 $var_line = $parts[0] . $has_no_cmt . $parts[2];
742 1452         4138 @parts = parse_for_variables ($var_line, 1, $opts);
743 1452         278795 ++$count_var;
744             }
745 16610         37347 push (@data, $var_line);
746              
747 16610         29753 my $unbalanced_leading_var_anchor_with_comments = 0;
748 16610 100 66     77146 if ( $cmt_found && $parts[0] =~ m/(\s*${comment}\s*)(.*$)/ ) {
    100          
749             # parts[1] is parts[7] trimmed ... so join back together with untrimmed.
750             $cmts = $2 . $opts->{variable_left} . $parts[7]
751 215         1533 . $opts->{variable_right} . $parts[2];
752 215         1345 my $str = convert_to_regexp_string ( $1 . $cmts );
753 215         37884 $line =~ s/${str}$//;
754 215         1076 DBUG_PRINT ("LINE", "Variables encountered with variables in comment ...");
755 215         27347 return DBUG_RETURN ( $tv_pair_flag, $line, $cmts, "", "");
756             } elsif ( $count_var ) {
757 1011 100       17514 if ( $var_line =~ m/(\s*${comment}\s*)(.*)$/ ) {
758 1005         3465 $cmts = $2;
759 1005 100       5019 if ( $cmts =~ m/${has_no_cmt}/ ) {
760 5         13 $unbalanced_leading_var_anchor_with_comments = 1;
761             } else {
762 1000         5148 my $cmt2 = convert_to_regexp_string ($1 . $cmts);
763 1000         172738 $line =~ s/${cmt2}$//;
764 1000         4460 DBUG_PRINT ("LINE", "Variables encountered with constant comment ...");
765             }
766             } else {
767 6         15 $cmts = "";
768 6         23 DBUG_PRINT ("LINE", "Variables encountered without comments ...");
769             }
770              
771 1011 100       130785 unless ( $unbalanced_leading_var_anchor_with_comments ) {
772 1006         3625 return DBUG_RETURN ( $tv_pair_flag, $line, $cmts, "", "");
773             }
774             }
775              
776             # ---------------------------------------------------------------------------
777             # Corrupted variable definition with variables in the comments ...
778             # Boy things are getting difficult to parse. Reverse the previous variable
779             # substitutions until the all variables in the comments are unexpanded again!
780             # Does a greedy RegExp to grab the 1st comment string encountered.
781             # ---------------------------------------------------------------------------
782 15389 100       46100 if ( $unbalanced_leading_var_anchor_with_comments ) {
783 5         14 $cmts = "";
784 5         16 foreach my $l (reverse @data) {
785 17 50       249 if ( $l =~ m/\s*${comment}\s*(.*)$/ ) {
786 17         36 $cmts = $1;
787 17 100       79 last unless ( $cmts =~ m/${has_no_cmt}/ );
788 12         25 $cmts = "";
789             }
790             }
791              
792 5 50       19 if ( $cmts ne "" ) {
793 5         19 my $cmt2 = convert_to_regexp_string ($cmts);
794 5         1504 $line =~ s/\s*${comment}\s*${cmt2}$//;
795 5         31 DBUG_PRINT ("LINE", "Unbalanced var def encountered with var comments ...");
796 5         1023 return DBUG_RETURN ( $tv_pair_flag, $line, $cmts, "", "");
797             }
798              
799             # If you get here, assume it's not a tag/value pair even if it is!
800             # I know I can no longer hope to parse it correctly without a test case.
801             # But I really don't think it's possible to get here anymore ...
802 0         0 warn ("Corrupted variable definition encountered. Can't split out the comment with variables in it correctly!\n");
803 0         0 return DBUG_RETURN ( 0, $line, "", "", "");
804             }
805              
806             # ----------------------------------------------------------------------
807             # No variables, no balanced quotes ...
808             # But I still think there's a comment to remove!
809             # ----------------------------------------------------------------------
810              
811 15384 100 66     194732 if ( $tv_pair_flag && $value =~ m/(\s*${comment}\s*)(.*)$/ ) {
812 12278         45187 $cmts = $2;
813 12278         61117 my $cmt2 = convert_to_regexp_string ($1 . $cmts);
814 12278         2470168 $line =~ s/${cmt2}$//; # Remove the comment from the line.
815 12278         67694 DBUG_PRINT ("LINE", "Last ditch effort to remove the comment from the value ...");
816 12278         1976568 return DBUG_RETURN ( $tv_pair_flag, $line, $cmts, "", "");
817             }
818              
819 3106         5579 $cmts = $line;
820 3106         35008 $line =~ s/\s*${comment}.*$//; # Strip off any comments ....
821 3106         11328 $cmts = substr ( $cmts, length ($line) ); # Grab the comments ...
822 3106         22173 $cmts =~ s/^\s*${comment}\s*//; # Remove comment symbol ...
823              
824 3106         12010 DBUG_PRINT ("LINE", "Last ditch effort to remove the comment from the line ...");
825 3106         290180 DBUG_RETURN ( $tv_pair_flag, $line, $cmts, "", "");
826             }
827              
828              
829             # ==============================================================
830              
831             =item ($v[, $h]) = expand_variables ( $config, $string[, $file[, $sensitive[, trim]]] )
832              
833             This function takes the provided I<$string> and expands any embedded variables
834             in this string similar to how it's handled by a Unix shell script.
835              
836             The optional I<$file> tells which file the string was read in from.
837              
838             The optional I<$sensitive> when set to a non-zero value is used to disable
839             B logging when it's turned on because the I<$string> being passed contains
840             sensitive information.
841              
842             The optional I<$trim> tells if you may trim the results before it's returned.
843              
844             It returns the new value $v, once all the variable substitution(s) have
845             occurred. And optionally a second return value $h that tells if B was
846             paused during the expansion of that value due to something being sensitive.
847             This 2nd return value $h is meaningless in most situations, so don't ask for it.
848              
849             All variables are defined as B<${>I<...>B<}>, where I<...> is the variable you
850             wish to substitute. If something isn't surrounded by a B<${> + B<}> pair, it's
851             not a variable.
852              
853             A config file exampe:
854             tmp1 = /tmp/work-1
855             tmp2 = /tmp/work-2
856             opt = 1
857             date = 2011-02-03
858             logs = ${tmp${opt}}/log-${date}.txt
859             date = 2012-12-13
860              
861             So when passed "${tmp${opt}}/log-${date}.txt", it would return:
862             /tmp/work-1/log-2011-02-03.txt
863             And assigned it to B.
864              
865             As you can see multiple variable substitutions may be expanded in a single
866             string as well as nested substitutions. And when the variable substitution is
867             done while reading in the config file, all the values used were defined before
868             the tag was referenced.
869              
870             Should you call this method after the config file was loaded you get slightly
871             different results. In that case the final tag value is used instead and the
872             2nd date in the above example would have been used in it's place.
873              
874             See L for more details on how it
875             evaluates individual variables.
876              
877             As a final note, if one or more of the referenced variables holds encrypted
878             values that haven't yet been decrypted, those variables are not resolved. But
879             all variables that don't contain encrypted data are resolved.
880              
881             =cut
882              
883             # ==============================================================
884             sub expand_variables
885             {
886 34097     34097 1 64900 my $config = shift; # For the current section of config obj ...
887 34097         69289 my $value = shift; # The value to parse for variables ...
888 34097   100     102109 my $file = shift || ""; # The config file the value came from ...
889 34097   100     125200 my $mask_flag = shift || 0; # Hide/mask sensitive info written to fish?
890 34097   100     105763 my $trim_flag = shift || 0; # Tells if we should trim the result or not.
891              
892             # Only mask ${value} if ${mask_flag} is true ...
893 34097 100       87111 DBUG_MASK_NEXT_FUNC_CALL (1) if ( $mask_flag );
894 34097         158159 DBUG_ENTER_FUNC ( $config, $value, $file, $mask_flag, $trim_flag, @_);
895              
896 34097         11760853 my $opts = $config->get_cfg_settings (); # The Read Options ...
897              
898 34097         6453257 my $pcfg = $config->get_section(); # Get the main/parent section to work with!
899              
900             # Don't write to Fish if we're hiding any values ...
901 34097 100       5952071 if ( $mask_flag ) {
902 575         2594 DBUG_PAUSE ();
903 575         201901 DBUG_MASK ( 0 );
904             }
905              
906             # The 1st split of the value into it's component parts ...
907 34097         133834 my ($left, $tag, $right, $cmt_flag, $mod_tag, $mod_opt, $mod_val, $ot) =
908             parse_for_variables ( $value, 0, $opts );
909              
910             # Any variables to substitute ???
911 34097 100       6900264 unless ( defined $tag ) {
912 29335         94192 return DBUG_RETURN ( $value, $mask_flag ); # nope ...
913             }
914              
915 4762         13237 my $output = $value;
916              
917 4762         9170 my %encrypt_vars;
918 4762         9250 my $encrypt_cnt = 0;
919 4762         9400 my $encrypt_fmt = "_"x50 . "ENCRYPT_%02d" . "-"x50;
920              
921             my ($lv, $rv) = ( convert_to_regexp_string ($opts->{variable_left}),
922 4762         21816 convert_to_regexp_string ($opts->{variable_right}) );
923              
924             # While there are still variables to process ...
925 4762         1168874 while ( defined $tag ) {
926 7755         1022997 my ( $val, $mask );
927 7755         15731 my $do_mod_lookup = 0; # Very rarely set to true ...
928              
929             # ${tag} and ${mod_tag} will never have the same value ...
930             # ${mod_tag} will amost always be undefinded.
931             # If both are defined, we'll almost always end up using ${mod_tag} as
932             # the real variable to expand! But we check to be sure 1st.
933              
934 7755         46792 ( $val, $mask ) = $config->lookup_one_variable ( $tag );
935              
936             # It's extreemly rare to have this "if statement" evalate to true ...
937 7755 100 100     2034463 if ( (! defined $val) && defined $mod_tag ) {
938 184         914 ( $val, $mask ) = $config->lookup_one_variable ( $mod_tag );
939              
940             # -----------------------------------------------------------------
941             # If we're using variable modifiers, it doesn't matter if the
942             # varible exists or not. The modifier gets evaluated!
943             # So checking if the undefined $mod_tag needs to be masked or not ...
944             # -----------------------------------------------------------------
945 184 100       44726 unless ( defined $val ) {
946 13         64 $mask = should_we_hide_sensitive_data ( $mod_tag );
947             }
948              
949 184         4282 $do_mod_lookup = 1; # Yes, apply the modifiers!
950             }
951              
952             # Use a place holder if the variable references data that is still encrypted.
953 7755 100       21939 if ( $mask == -1 ) {
954 35         95 $mask_flag = -1;
955 35         279 $val = sprintf ($encrypt_fmt, ++$encrypt_cnt);
956              
957             # If the place holder contains variable anchors abort the substitutions.
958 35 50 33     565 last if ( $val =~ m/${lv}/ || $val =~ m/${rv}/ );
959              
960 35         174 $encrypt_vars{$val} = $tag;
961 35         73 $do_mod_lookup = 0;
962             }
963              
964             # Doing some accounting to make sure any sensitive data doesn't
965             # show up in the fish logs from now on.
966 7755 100 100     23532 if ( $mask && ! $mask_flag ) {
967 126         291 $mask_flag = 1;
968 126         548 DBUG_PAUSE ();
969 126         45191 DBUG_MASK ( 0 );
970             }
971              
972 7755 100       26112 if ( $do_mod_lookup ) {
973 175         394 my $m;
974 175         718 ($val, $m) = apply_modifier ( $config, $val, $mod_tag, $mod_opt, $mod_val, $file );
975 175 100 100     37642 if ( $m == -2 ) {
    100          
976             # The name of the variable changed & points to an encrypted value.
977 8         47 $val = $opts->{variable_left} . ${val} . $opts->{variable_right};
978             } elsif ( $m && ! $mask_flag ) {
979 21         51 $mask_flag = 1;
980 21         80 DBUG_PAUSE ();
981 21         7205 DBUG_MASK ( 0 );
982             }
983             }
984              
985             # Rebuild the output string so we can look for more variables ...
986 7755 100       20903 if ( defined $val ) {
987 7270         18914 $output = $left . $val . $right;
988             } else {
989 485         1519 $output = $left . $right;
990             }
991              
992             # Get the next variable to evaluate ...
993 7755         25675 ($left, $tag, $right, $cmt_flag, $mod_tag, $mod_opt, $mod_val, $ot) =
994             parse_for_variables ( $output, 0, $opts );
995             } # End while ( defined $tag ) loop ...
996              
997              
998             # Restore all place holders back into the output string with the
999             # proper variable name. Have to assume still sensitive even if
1000             # all the placeholders drop out. Since can't tell what else may
1001             # have triggered it.
1002 4762 100       1389287 if ( $mask_flag == -1 ) {
1003 30         86 $mask_flag = 1; # Mark sensitive ...
1004 30         129 foreach ( keys %encrypt_vars ) {
1005 35         149 my $val = $opts->{variable_left} . $encrypt_vars{$_} . $opts->{variable_right};
1006 35 100       584 $mask_flag = -1 if ( $output =~ s/$_/$val/ );
1007             }
1008             }
1009              
1010             # Did the variable substitution result in the need to trim things?
1011 4762 100       14977 if ( $trim_flag ) {
1012 3936         17809 $output =~ s/^\s+//;
1013 3936         14279 $output =~ s/\s+$//;
1014             }
1015              
1016 4762         16511 DBUG_RETURN ( $output, $mask_flag );
1017             }
1018              
1019              
1020             # ==============================================================
1021              
1022             =item ($v[, $s]) = apply_modifier ( $config, $value, $tag, $rule, $sub_rule, $file )
1023              
1024             This is a helper method to F. Not for public use.
1025              
1026             This function takes the rule specified by I<$rule> and applies it against
1027             the I<$value> with assistance from the I<$sub_rule>.
1028              
1029             It returns the edited I and whether applying the modifier made it
1030             I. (-1 means it's an encrypted value. -2 means it's the variable
1031             name that resolves to an encrypted value. 0 - Non-sensitive, 1 - Sensitive.)
1032              
1033             See L
1034             for information on how this can work. This module supports most of the
1035             parameter expansions listed there except for those dealing with arrays. Other
1036             modifier rules may be added upon request.
1037              
1038             =cut
1039              
1040             # NOTE1: Fish has already been paused if $tag is sensitive. Since this method
1041             # has no idea if the current tag is sensitive or not.
1042              
1043             # NOTE2: But still need to mask the return value if referencing sensitive data
1044             # in case the original $tag wasn't sensitive. So in most cases it will
1045             # return not-sensitive even if fish has already been paused!
1046             #
1047             # NOTE3: If sensitive/mask is -1, it's sensitive and not decrypted. In this
1048             # case the returned value is the tag's name, not it's value!
1049              
1050             sub apply_modifier
1051             {
1052 175     175 1 720 DBUG_ENTER_FUNC ( @_ );
1053 175         78874 my $cfg = shift;
1054 175         410 my $value = shift; # The value for ${mod_tag} ...
1055 175         361 my $mod_tag = shift; # The tag to apply the rule against!
1056 175         352 my $mod_opt = shift; # The rule ...
1057 175         348 my $mod_val = shift; # The sub-rule ...
1058 175         342 my $file = shift; # The file the tag's from.
1059              
1060 175 100       584 my $alt_val = (defined $value) ? $value : "";
1061              
1062             # The values to return ...
1063 175         314 my $output;
1064              
1065             # Values: 0 - Normal non-sensitive return value (99.9% of the time)
1066             # 1 - Sensitive return value.
1067             # -1 - Return value is encrypted.
1068             # -2 - Return value is variable name of encrypted value.
1069 175         398 my $mask = 0;
1070              
1071             # If looking for a default value ...
1072 175 100 100     5103 if ( ( $mod_opt eq ":+" && $alt_val ne "" ) ||
    100 100        
    100 100        
    100 100        
    100 100        
    100 100        
    100 100        
    100 100        
    100 100        
    100 100        
    100          
    100          
    100          
    100          
1073             ( $mod_opt =~ m/^:[-=?]$/ && $alt_val eq "" ) ||
1074             ( $mod_opt eq "+" && defined $value ) ||
1075             ( $mod_opt =~ m/^[-=?]$/ && ! defined $value ) ) {
1076 9         36 $output = $mod_val; # Now uses this value as it's default!
1077              
1078 9 100 100     86 if ( $mod_opt eq ":=" || $mod_opt eq "=" ) {
    50 33        
1079             # The variable either doesn't exist or it resolved to "".
1080             # This variant rule says to also set the variable to this value!
1081 2         15 $cfg->_base_set ( $mod_tag, $output, $file );
1082              
1083             } elsif ( $mod_opt eq ":?" || $mod_opt eq "?" ) {
1084             # In shell scripts, ":?" would cause your script to die with the
1085             # default value as the error message if your var had no value.
1086             # Repeating that logic here.
1087 0         0 my $msg = "Encounterd undefined variable ($mod_tag) using shell modifier ${mod_opt}";
1088 0 0       0 $msg .= " in config file: " . basename ($file) if ( $file ne "" );
1089 0         0 DBUG_PRINT ("MOD", $msg);
1090 0         0 die ( basename ($0) . ": ${mod_tag}: ${output}.\n" );
1091             }
1092              
1093 9         40 DBUG_PRINT ("MOD",
1094             "The modifier (%s) is overriding the variable with a default value!",
1095             $mod_opt);
1096              
1097             # Sub-string removal ...
1098             } elsif ( $mod_opt eq "##" || $mod_opt eq "#" || # From beginning
1099             $mod_opt eq "%%" || $mod_opt eq "%" ) { # From end
1100 11   100     36 my $greedy = ( $mod_opt eq "##" || $mod_opt eq "%%" );
1101 11   100     31 my $leading = ( $mod_opt eq "#" || $mod_opt eq "##" );
1102 11         16 my $reverse_msg = ""; # Both the message & control flag ...
1103              
1104 11         17 $output = $alt_val;
1105              
1106             # Now replace shell script wildcards with their Perl equivalents.
1107             # A RegExp can't do non-greedy replaces anchored to the end of string!
1108             # So we need the reverse logic to do so.
1109 11         34 my $regExpVal = convert_to_regexp_modifier ($mod_val);
1110 11         2223 $regExpVal =~ s/[?]/./g; # ? --> . (any one char)
1111 11 100       39 if ( $greedy ) {
    100          
    50          
1112 4         16 $regExpVal =~ s/[*]/.*/g; # * --> .* (zero or more greedy chars)
1113             } elsif ( $leading ) {
1114 4         15 $regExpVal =~ s/[*]/(.*?)/g; # * --> (.*?) (zero or more chars)
1115             } elsif ( $regExpVal =~ m/[*]/ ) {
1116             # Non-Greedy with one or more wild cards present ("*")!
1117 3         6 $leading = 1; # Was false before.
1118 3         7 $regExpVal = reverse ($regExpVal);
1119 3         10 $regExpVal =~ s/[*]/(.*?)/g; # * --> (.*?) (zero or more chars)
1120 3         7 $output = reverse ($output);
1121 3         5 $reverse_msg = " Reversed for non-greedy strip.";
1122             }
1123              
1124 11 100       25 if ( $leading ) {
1125 8         14 $regExpVal = '^' . $regExpVal;
1126             } else {
1127             # Either greedy trailing or no *'s in trailing regular expression!
1128 3         7 $regExpVal .= '$';
1129             }
1130              
1131 11         186 $output =~ s/${regExpVal}//; # Strip off the matching values ...
1132 11 100       33 $output = reverse ($output) if ( $reverse_msg ne "" );
1133              
1134 11         32 DBUG_PRINT ("MOD",
1135             "The modifier (%s) converted \"%s\" to \"%s\".%s\nTo trim the value to: %s",
1136             $mod_opt, $mod_val, $regExpVal, $reverse_msg, $output);
1137              
1138             } elsif ( $mod_opt eq "LENGTH" ) {
1139 1         3 $output = length ( $alt_val );
1140 1         4 DBUG_PRINT ("MOD", "Setting the length of variable \${#%s} to: %d.",
1141             $mod_tag, $output);
1142              
1143             } elsif ( $mod_opt eq "LIST" ) {
1144 2         12 my @lst = $cfg->_find_variables ( $mod_val );
1145 2         489 $output = join (" ", @lst);
1146 2         6 DBUG_PRINT ("MOD", "Getting all varriables starting with %s", $mod_val);
1147              
1148             } elsif ( $mod_opt eq "!" ) {
1149 108         533 ($output, $mask) = $cfg->lookup_one_variable ( $alt_val );
1150 108 100       22034 if ( $mask == -1 ) {
    100          
1151 8         22 $mask = -2; # Indirect reference to encrypted value
1152 8         23 $output = $alt_val; # Replace with new variable name
1153             } elsif ( $mask ) {
1154 48         184 DBUG_MASK (0);
1155             }
1156 108         1881 DBUG_PRINT ("MOD", "Indirectly referencing variable %s (%s)", $alt_val, $mask);
1157              
1158             } elsif ( $mod_opt eq "//" ) {
1159 4         53 my ($ptrn, $val) = split ("/", $mod_val);
1160 4         13 $output = $alt_val;
1161 4         50 $output =~ s/${ptrn}/${val}/g;
1162 4         24 DBUG_PRINT ("MOD", "Global replacement in %s", $alt_val);
1163              
1164             } elsif ( $mod_opt eq "/" ) {
1165 8         35 my ($ptrn, $val) = split ("/", $mod_val);
1166 8         20 $output = $alt_val;
1167 8         155 $output =~ s/${ptrn}/${val}/;
1168 8         33 DBUG_PRINT ("MOD", "1st replacement in %s", $alt_val);
1169              
1170             } elsif ( $mod_opt eq ":" ) {
1171 8         31 my ($offset, $length) = split (":", $mod_val);
1172 8 100 66     45 if ( defined $length && $length ne "" ) {
1173 7         23 $output = substr ( $alt_val, $offset, $length);
1174             } else {
1175 1         4 $output = substr ( $alt_val, $offset);
1176             }
1177 8         18 DBUG_PRINT ("MOD", "Substring (%s)", $output);
1178              
1179             # The 6 case manipulation modifiers ...
1180             } elsif ( $mod_opt eq "^^" ) {
1181 2         8 $output = uc ($alt_val);
1182 2         8 DBUG_PRINT ("MOD", "Upshift string (%s)", $output);
1183             } elsif ( $mod_opt eq ",," ) {
1184 1         2 $output = lc ($alt_val);
1185 1         4 DBUG_PRINT ("MOD", "Downshift string (%s)", $output);
1186             } elsif ( $mod_opt eq "~~" ) {
1187 1         2 $output = $alt_val;
1188 1 100       6 $output =~ s/([A-Z])|([a-z])/defined $1 ? lc($1) : uc($2)/gex;
  23         45  
1189 1         3 DBUG_PRINT ("MOD", "Reverse case of each char in string (%s)", $output);
1190             } elsif ( $mod_opt eq "^" ) {
1191 1         5 $output = ucfirst ($alt_val);
1192 1         5 DBUG_PRINT ("MOD", "Upshift 1st char in string (%s)", $output);
1193             } elsif ( $mod_opt eq "," ) {
1194 1         4 $output = lcfirst ($alt_val);
1195 1         5 DBUG_PRINT ("MOD", "Downshift 1st char in string (%s)", $output);
1196             } elsif ( $mod_opt eq "~" ) {
1197 1         3 $output = ucfirst ($alt_val);
1198 1 50       3 $output = lcfirst ($alt_val) if ( $alt_val eq $output );
1199 1         4 DBUG_PRINT ("MOD", "Reverse case of 1st char in string (%s)", $output);
1200              
1201             } else {
1202 17         89 DBUG_PRINT ("MOD",
1203             "The modifier (%s) didn't affect the variable's value!",
1204             $mod_opt);
1205 17         4699 $output = $value;
1206             }
1207              
1208 175         31613 DBUG_RETURN ( $output, $mask );
1209             }
1210              
1211              
1212             # ==============================================================
1213              
1214             =item @ret[0..7] = parse_for_variables ( $value, $ignore_disable_flag, $rOpts )
1215              
1216             This is a helper method to F and B.
1217              
1218             This method parses the I<$value> to see if any variables are defined in it
1219             and returns the information about it. If there is more than one variable
1220             present in the I<$value>, only the 1st variable/tag to evaluate is returned.
1221              
1222             By default, a variable is the tag in the I<$value> between B<${> and B<}>, which
1223             can be overridden with other anchor patterns. See L
1224             for more details on this.
1225              
1226             If you've configured the module to ignore variables, it will never find any.
1227             Unless you also set I<$ignore_disable_flag> to a non-zero value.
1228              
1229             Returns B<8> values. ( $left, $tag, $right, $cmt, $sub_tag, $sub_opr, $sub_val,
1230             $otag )
1231              
1232             All B<8> values will be I if no variables were found in I<$value>.
1233              
1234             Otherwise it returns at least the 1st four values. Where I<$tag> is the
1235             variable that needs to be looked up. And the caller can join things back
1236             together as "B<$left . $look_up_value . $right>" after the variable substitution
1237             is done and before this method is called again to locate additional variables in
1238             the resulting new I<$value>.
1239              
1240             The 4th value I<$cmt>, will be true/false based on if B<$left> has a comment
1241             symbol in it! This flag only has meaning to B. And is terribly
1242             misleading to other users.
1243              
1244             Should the I<$tag> definition have one of the supported shell script variable
1245             modifiers embedded inside it, then the I<$tag> will be parsed and the 3 B
1246             return values will be calculated as well. See
1247             L for more details. Most of the
1248             modifiers listed there are supported except for those dealing with arrays.
1249             See I for applying these rules against the returned I<$tag>.
1250             Other modifier rules may be added upon request.
1251              
1252             These 3 B return values will always be I should the variable
1253             left/right anchors be overridden with the same value. Or if no modifiers
1254             are detected in the tag's name.
1255              
1256             If you've configured the module to be case insensitive (option B),
1257             then both I<$tag> and I<$sub_tag> will be shifted to lower case for case
1258             insensitive variable lookups.
1259              
1260             Finally there is an 8th return value, I<$otag>, that contains the original
1261             I<$tag> value before it was edited. Needed by F logic.
1262              
1263             =cut
1264              
1265             # WARNING: If (${lvar} == ${rvar}), nested variables are not supported.
1266             # : And neither are variable modifiers. (The sub_* return values.)
1267             # : So evaluate tags left to right.
1268             # : If (${lvar} != ${rvar}), nested variables are supported.
1269             # : So evaluate inner most tags first. And then left to right.
1270             #
1271             # RETURNS: 8 values. ( $left, $tag, $right, $cmt, $sub_tag, $sub_opr, $sub_val, $otag )
1272             # : The 3 sub_* vars are usually undef.
1273             # : But when set, all 3 sub_* vars are set! And $tag != $sub_tag.
1274             #
1275             # NOTE 1 : If the 3 sub_* vars are populated, you'd get something like this
1276             # : for the tag & sub_* vars.
1277             # : tag : "abc:-Default Value" - the ${...} was removed.
1278             # : sub_tag : "abc" - the ${...} & modifier were removed.
1279             # : sub_opr : ":-"
1280             # : sub_val : "Default Value"
1281             # : So if the "tag" exists as a variable, the sub_* values are ignored.
1282             # : But if "tag" doesn't exist as a variable, then we apply the
1283             # : sub_* rules!
1284             #
1285             # NOTE 2 : If the sub_* vars undef, you'd get something like this without any
1286             # : modifiers.
1287             # : tag : tag - the ${...} was removed.
1288             #
1289             # NOTE 3 : For some alternate variable anchors, the sub_* vars will almost
1290             # : always be undef. Since the code base won't allow you to redefine
1291             # : these modifiers when they conflict with the variable anchors.
1292              
1293             sub parse_for_variables
1294             {
1295 59914     59914 1 213573 DBUG_ENTER_FUNC ( @_ );
1296 59914         21863341 my $value = shift;
1297 59914         125266 my $disable_flag = shift;
1298 59914         110468 my $opts = shift;
1299              
1300 59914         120098 my ($left, $s1, $tag, $s2, $right, $otag);
1301 59914         96633 my $cmt_flg = 0;
1302 59914         111838 my ($sub_tag, $sub_opr, $sub_val, $sub_extra);
1303              
1304 59914 100 100     236163 if ( $opts->{disable_variables} && (! $disable_flag) ) {
1305 7         32 DBUG_PRINT ("INFO", "Variable substitution has been disabled.");
1306 7         1392 return DBUG_RETURN ( $left, $tag, $right, $cmt_flg,
1307             $sub_tag, $sub_opr, $sub_val, $otag );
1308             }
1309              
1310 59907         217270 my $lvar = convert_to_regexp_string ($opts->{variable_left}, 1);
1311 59907         169407 my $rvar = convert_to_regexp_string ($opts->{variable_right}, 1);
1312              
1313             # Break up the value into it's component parts. (Non-greedy RegExpr)
1314 59907 100       514257 if ( $value =~ m/(^.*?)(${lvar})(.*?)(${rvar})(.*$)/ ) {
1315 9422         79825 ($left, $s1, $tag, $s2, $right) = ($1, $2, $3, $4, $5);
1316 9422         20477 $otag = $tag;
1317              
1318             # Did a comment symbol apear before the 1st ${lvar} in the line?
1319 9422         28565 my $cmt_str = convert_to_regexp_string ($opts->{comment}, 1);
1320 9422 100       61476 $cmt_flg = 1 if ( $left =~ m/${cmt_str}/ );
1321              
1322 9422         37118 DBUG_PRINT ("XXXX", "%s ===> %s <=== %s -- %d",
1323             $left, $tag, $right, $cmt_flg);
1324              
1325             # We know we found the 1st right hand anchor in the string's value.
1326             # But since variables may be nested, we might not be at the correct
1327             # left hand anchor. But at least we know they're going to balance!
1328              
1329             # Check for nested variables ... (trim left side)
1330 9422         2264504 while ( $tag =~ m/(^.*)${lvar}(.*?$)/ ) {
1331 1022         5158 my ($l, $t) = ($1, $2);
1332 1022         2569 $left .= $s1 . $l;
1333 1022         5229 $tag = $t;
1334             }
1335              
1336             # Strip off leading spaces from the tag's name.
1337             # No tag may have leading spaces in it.
1338             # Defering the stripping of trailing spaces until later on purpose!
1339 9422         36032 $tag =~ s/^\s+//;
1340              
1341             # -----------------------------------------------------------
1342             # We have a variable! Now check if there are modifiers
1343             # in it that we are supporting ...
1344             # See: http://wiki.bash-hackers.org/syntax/pe
1345             # -----------------------------------------------------------
1346              
1347             # The variable modifier tags. Needed to avoid using the wrong rule.
1348             # A variable name can use anything except for what's in this list!
1349 9422         19242 my $not = "[^-:?+#%/\^,~]";
1350              
1351 9422 100 100     492390 if ( $lvar eq $rvar ) {
    100 100        
    100 100        
    100 66        
    100 66        
    100 100        
    100 100        
    100 100        
    100 100        
    100          
    100          
    100          
    100          
1352             ; # No modifiers are supported if the left/right anchors are the same!
1353             # Since there are too many modifier/anchor pairs that no longer
1354             # work. Behaving more like a Windows *.bat file now.
1355              
1356             } elsif ( $opts->{disable_variable_modifiers} ) {
1357             ; # Explicitly told not to use this feature.
1358              
1359             # Rule: :-, :=, :+, -, =, or +
1360             } elsif ( $tag =~ m/(^${not}+)(:?[-=+])(.+)$/) {
1361 59         341 ($sub_tag, $sub_opr, $sub_val) = ($1, $2, $3);
1362              
1363             # Rule: :? or ?
1364             } elsif ( $tag =~ m/(^${not}+)(:?[?])(.*)$/) {
1365 7         44 ($sub_tag, $sub_opr, $sub_val) = ($1, $2, $3);
1366 7 100       24 $sub_val = "Parameter null or not set." if ( $sub_val eq "" );
1367              
1368             # Rule: ##, %%, #, or %
1369             } elsif ( $tag =~ m/^(${not}+)(##)(.+)$/ ||
1370             $tag =~ m/^(${not}+)(%%)(.+)$/ ||
1371             $tag =~ m/^(${not}+)(#)(.+)$/ ||
1372             $tag =~ m/^(${not}+)(%)(.+)$/ ) {
1373 42         187 ($sub_tag, $sub_opr, $sub_val) = ($1, $2, $3);
1374              
1375             # Rule: Get length of variable's value ...
1376             } elsif ( $tag =~ m/^#(.+)$/ ) {
1377             # Using LENGTH for ${#var} opt since "#" is already used above!
1378 16         53 ($sub_tag, $sub_opr, $sub_val) = ($1, "LENGTH", "");
1379 16         40 $sub_tag =~ s/^\s+//;
1380              
1381             # Rule: ${!var*} & ${!var@} ...
1382             } elsif ( $tag =~ m/^!(.+)[@*]$/ ) {
1383             # Using LIST for ${!var*} & ${!var@} opts since "!" has another meaning.
1384 2         15 ($sub_tag, $sub_opr, $sub_val) = ($1, "LIST", convert_to_regexp_string ($1));
1385 2         430 $sub_tag =~ s/^\s+//;
1386              
1387             # Rule: Indirect lookup ...
1388             } elsif ( $tag =~ m/^!(.+)$/ ) {
1389 140         853 ($sub_tag, $sub_opr, $sub_val) = ($1, "!", "");
1390 140         498 $sub_tag =~ s/^\s+//;
1391              
1392             # Rule: Substitution logic ... ( / vs // )
1393             # Anchors # or % supported but no RegExp wildcards are.
1394             } elsif ( $tag =~ m#^(${not}+)(//?)([^/]+)/([^/]*)$# ) {
1395 14         126 ($sub_tag, $sub_opr, $sub_val, $sub_extra) = ($1, $2, $3, $4);
1396 14         56 $sub_val = convert_to_regexp_string ($sub_val);
1397              
1398 14 100       4071 if ( $sub_val =~ m/^([#%])(.+)$/ ) {
1399 4         12 $sub_val = $2;
1400 4 100       18 $sub_val = ( $1 eq "#" ) ? "^${sub_val}/${sub_extra}" : "${sub_val}\$/${sub_extra}";
1401             } else {
1402 10         34 $sub_val = "${sub_val}/${sub_extra}";
1403             }
1404 14         34 $sub_val .= "/x";
1405              
1406             # Rule: Another format for the Substitution logic ... ( / vs // )
1407             } elsif ( $tag =~ m#^(${not}+)(//?)([^/]+)$# ) {
1408 6         30 ($sub_tag, $sub_opr, $sub_val, $sub_extra) = ($1, $2, $3, "");
1409 6         17 $sub_val = convert_to_regexp_string ($sub_val);
1410              
1411 6 100       1513 if ( $sub_val =~ m/^([#%])(.+)$/ ) {
1412 4         41 $sub_val = $2;
1413 4 100       21 $sub_val = ( $1 eq "#" ) ? "^${sub_val}/${sub_extra}" : "${sub_val}\$/${sub_extra}";
1414             } else {
1415 2         7 $sub_val = "${sub_val}/${sub_extra}";
1416             }
1417 6         14 $sub_val .= "/x";
1418              
1419             # Rule: Substring expansion ... ${MSG:OFFSET}
1420             } elsif ( $tag =~ m#^(${not}+):([0-9]+)$# ||
1421             $tag =~ m#^(${not}+):\s+(-[0-9]+)$# ||
1422             $tag =~ m#^(${not}+):[(](-[0-9]+)[)]$# ) {
1423 1         3 ($sub_tag, $sub_opr, $sub_val) = ($1, ":", $2);
1424 1         2 $sub_val .= ":"; # To the end of the string ...
1425              
1426             # Rule: Substring expansion ... ${MSG:OFFSET:LENGTH}
1427             } elsif ( $tag =~ m#^(${not}+):([0-9]+):(-?[0-9]+)$# ||
1428             $tag =~ m#^(${not}+):\s+(-[0-9]+):(-?[0-9]+)$# ||
1429             $tag =~ m#^(${not}+):[(](-[0-9]+)[)]:(-?[0-9]+)$# ) {
1430 7         32 ($sub_tag, $sub_opr, $sub_val, $sub_extra) = ($1, ":", $2, $3);
1431 7         14 $sub_val .= ":${sub_extra}";
1432              
1433             # Rule: Case manipulation ... (6 variants)
1434             } elsif ( $tag =~ m/^(${not}+)([\^]{1,2})$/ ||
1435             $tag =~ m/^(${not}+)([,]{1,2})$/ ||
1436             $tag =~ m/^(${not}+)([~]{1,2})$/ ) {
1437 13         58 ($sub_tag, $sub_opr, $sub_val) = ($1, $2, "");
1438              
1439             } else {
1440             ; # No variable modifiers were found!
1441             }
1442              
1443             # Strip off any trailing spaces from the tag & sub-tag names ...
1444 9422         39177 $tag =~ s/\s+$//;
1445 9422 100       27127 $sub_tag =~ s/\s+$// if ( defined $sub_tag );
1446             } # End "if" a tag/variable was found in ${value} ...
1447              
1448             # Are we using case insensitive tags/variables?
1449             # If so, all varibles must be in lower case ...
1450             # Leave $otag alone.
1451 59907 100       165111 if ( $opts->{tag_case} ) {
1452 12 100       70 $tag = lc ($tag) if ( defined $tag );
1453 12 50       48 $sub_tag = lc ($sub_tag) if ( defined $sub_tag );
1454             }
1455              
1456 59907         225351 DBUG_RETURN ( $left, $tag, $right, $cmt_flg, $sub_tag, $sub_opr, $sub_val,
1457             $otag );
1458             }
1459              
1460              
1461             # ==============================================================
1462              
1463             =item $string = format_section_line ( $name, \%rOpts )
1464              
1465             Uses the given I to generate a section string
1466             from I<$name>.
1467              
1468             =cut
1469              
1470             sub format_section_line
1471             {
1472 6     6 1 41 DBUG_ENTER_FUNC ( @_ );
1473 6         3799 my $name = shift; # The name of the section ...
1474 6         21 my $rOpts = shift;
1475              
1476 6         57 DBUG_RETURN ( $rOpts->{section_left} . " ${name} " . $rOpts->{section_right} );
1477             }
1478              
1479              
1480             # ==============================================================
1481              
1482             =item $string = format_tag_value_line ( $cfg, $tag, \%rOpts )
1483              
1484             It looks up the B in the I<$cfg> object, then it uses the given
1485             I options to format a tag/value pair string.
1486              
1487             =cut
1488              
1489             sub format_tag_value_line
1490             {
1491 24     24 1 129 DBUG_ENTER_FUNC ( @_ );
1492 24         15172 my $cfg = shift; # An Advanced::Config object reference.
1493 24         73 my $tag = shift;
1494 24         62 my $rOpts = shift;
1495              
1496 24         194 my ($value, $sensitive) = $cfg->_base_get2 ( $tag, {required => 1} );
1497 24 100       205 DBUG_MASK (0) if ( $sensitive );
1498              
1499             # Determine if we're alowed to surround things with quotes ...
1500 24         499 my ($quote_l, $quote_r); # Assume no!
1501 24 50       120 if (using_default_quotes ( $rOpts )) {
    0          
1502 24 100 100     7423 if ( $value =~ m/'/ && $value =~ m/"/ ) {
    100          
    50          
1503 3         12 my $noop; # No quotes allowed!
1504             } elsif ( $value !~ m/'/ ) {
1505 18         83 $quote_l = $quote_r = "'";
1506             } elsif ( $value !~ m/"/ ) {
1507 3         13 $quote_l = $quote_r = '"';
1508             }
1509              
1510             } elsif ( ! $rOpts->{disable_quotes} ) {
1511             my ($ql, $qr) = ( convert_to_regexp_string ($rOpts->{quote_left}, 1),
1512 0         0 convert_to_regexp_string ($rOpts->{quote_right}, 1) );
1513 0 0 0     0 unless ( $value =~ m/${ql}/ || $value =~ m/${qr}/ ) {
1514 0         0 $quote_l = $rOpts->{quote_left};
1515 0         0 $quote_r = $rOpts->{quote_right};
1516             }
1517             }
1518              
1519             # Do we have to correct for having comments in the value?
1520 24         235 my $cmt = convert_to_regexp_string ($rOpts->{comment}, 1);
1521 24 100       310 if ( $value =~ m/${cmt}/ ) {
1522 12         41 my $err = "Can't do toString() due to using comments in the value of '${tag}'\n";
1523              
1524 12 50       79 if ( $rOpts->{disable_variables} ) {
1525 0 0       0 if ( $rOpts->{disable_quotes} ) {
1526 0         0 die ($err, "when you've also disabled both quotes & variables!\n");
1527             }
1528 0 0       0 unless ( $quote_l ) {
1529 0         0 die ($err, "when you've disabled variables while there are quotes in the value as well!\n");
1530             }
1531             }
1532              
1533             # Convert the comment symbols to the special variable if no quotes are allowed.
1534 12 100       58 unless ( $quote_l ) {
1535 3         17 my $v = $rOpts->{variable_left} . "shft3" . $rOpts->{variable_right};
1536 3         116 $value =~ s/${cmt}/${v}/g;
1537             }
1538             }
1539              
1540             # Surround the value with quotes!
1541 24 100       113 if ( $quote_l ) {
1542 21         88 $value = ${quote_l} . ${value} . ${quote_r};
1543             }
1544              
1545 24         120 my $line = ${tag} . " " . $rOpts->{assign} . " " . ${value};
1546              
1547 24         107 DBUG_RETURN ( $line );
1548             }
1549              
1550              
1551             # ==============================================================
1552              
1553             =item $string = format_encrypt_cmt ( \%rOpts )
1554              
1555             Uses the given I to generate a comment suitable for use
1556             in marking a tag/value pair as ready to be encrypted.
1557              
1558             =cut
1559              
1560             sub format_encrypt_cmt
1561             {
1562 2     2 1 14 DBUG_ENTER_FUNC ( @_ );
1563 2         1240 my $rOpts = shift;
1564              
1565 2         16 DBUG_RETURN ( $rOpts->{comment} . " " . $rOpts->{encrypt_lbl} );
1566             }
1567              
1568              
1569             # ==============================================================
1570              
1571             =item $status = encrypt_config_file_details ( $file, $writeFile, \%rOpts )
1572              
1573             This function encrypts all tag values inside the specified config file that are
1574             marked as ready for encryption and generates a new config file with everything
1575             encrypted. If a tag/value pair isn't marked as ready for encryption it is left
1576             alone. By default this label is B.
1577              
1578             After a tag's value has been encrypted, the label in the comment is updated
1579             from B to B in the new file.
1580              
1581             If you are adding new B tags to an existing config file that already
1582             has B tags in it, you must use the same encryption related options in
1583             I<%rOpts> as the last time. Otherwise you won't be able to decrypt all
1584             encrypted values.
1585              
1586             This method ignores any request to source in other config files. You must
1587             encrypt each file individually.
1588              
1589             It writes the results of the encryption process to I<$writeFile>.
1590              
1591             See L for some caveats about this process.
1592              
1593             Returns: B<1> if something was encrypted. B<-1> if nothing was encrypted.
1594             Otherwise B<0> on error.
1595              
1596             =cut
1597              
1598             sub encrypt_config_file_details
1599             {
1600 7     7 1 43 DBUG_ENTER_FUNC ( @_ );
1601 7         4155 my $file = shift;
1602 7         20 my $scratch = shift;
1603 7         24 my $rOpts = shift;
1604              
1605 7         349 unlink ( $scratch );
1606              
1607             # The labels to search for ...
1608 7         58 my $decrypt_str = convert_to_regexp_string ($rOpts->{decrypt_lbl});
1609 7         2318 my $encrypt_str = convert_to_regexp_string ($rOpts->{encrypt_lbl});
1610 7         2186 my $hide_str = convert_to_regexp_string ($rOpts->{hide_lbl});
1611              
1612 7         1808 my $assign_str = convert_to_regexp_string ($rOpts->{assign});
1613             my ($lb, $rb) = ( convert_to_regexp_string ($rOpts->{section_left}),
1614 7         1686 convert_to_regexp_string ($rOpts->{section_right}) );
1615              
1616             # The label separators used when searching for option labels in a comment ...
1617 7         2284 my $lbl_sep = '[\s.,$!-()]';
1618              
1619 7         18 my $mask = "*"x8;
1620              
1621 7         32 DBUG_PRINT ("INFO", "Opening for reading the config file named: %s", $file);
1622              
1623 7 50       1826 unless ( open (ENCRYPT, "<", $file) ) {
1624 0         0 return DBUG_RETURN ( croak_helper ($rOpts,
1625             "Unable to open the config file.", 0) );
1626             }
1627              
1628 7         63 DBUG_PRINT ("INFO", "Creating scratch file named: %s", $scratch);
1629 7 50       2539 unless ( open (NEW, ">", $scratch) ) {
1630 0         0 close (ENCRYPT);
1631 0         0 return DBUG_RETURN ( croak_helper ($rOpts,
1632             "Unable to create the scratch config file.", 0) );
1633             }
1634              
1635             # Misuse of this option makes the config file unreadable ...
1636 7 100       52 if ( $rOpts->{use_utf8} ) {
1637 1         58 binmode (ENCRYPT, "encoding(UTF-8)");
1638 1         303 binmode (NEW, "encoding(UTF-8)");
1639             }
1640              
1641 7         418 my $errMsg = "Unable to write to the scratch file.";
1642              
1643 7         18 my $hide_section = 0;
1644 7         17 my $count = 0;
1645              
1646 7         253 while ( ) {
1647 7314         23974 chomp;
1648 7314         16304 my $line = $_;
1649              
1650 7314         26364 my ($tv, $ln, $cmt, $lq, $rq) = parse_line ( $line, $rOpts );
1651              
1652 7314         2228689 my ($hide, $encrypt) = (0, 0);
1653 7314         20716 my ($tag, $value, $prefix, $t2);
1654 7314 100       32006 if ( $tv ) {
    100          
1655 6652         21657 ($tag, $value, $prefix, $t2) = _split_assign ( $rOpts, $ln );
1656              
1657 6652 100       72526 if ( $cmt =~ m/(^|${lbl_sep})${encrypt_str}(${lbl_sep}|$)/ ) {
    50          
1658 6131         17176 ($hide, $encrypt) = (1, 1);
1659              
1660             # Don't hide the decrypt string ... (already unreadable)
1661             } elsif ( $cmt =~ m/(^|${lbl_sep})${hide_str}(${lbl_sep}|$)/ ) {
1662 0         0 $hide = 1;
1663              
1664             } else {
1665 521 100 66     2212 if ( $hide_section || should_we_hide_sensitive_data ( $tag, 1 ) ) {
1666 2         8 $hide = 1;
1667             }
1668             }
1669              
1670             # Is it a section whose contents we need to hide???
1671             } elsif ( $ln =~ m/^${lb}\s*(.+?)\s*${rb}$/ ) {
1672 109         677 my $section = lc ($1);
1673 109 50       588 $hide_section = should_we_hide_sensitive_data ( $section, 1 ) ? 1 : 0;
1674             }
1675              
1676 7314 100       26578 unless ( $hide ) {
1677 1181         4794 DBUG_PRINT ("ENCRYPT", $line);
1678 1181 50       282940 unless (print NEW $line, "\n") {
1679 0         0 return DBUG_RETURN ( croak_helper ($rOpts, $errMsg, 0) );
1680             }
1681 1181         14887 next;
1682             }
1683              
1684             # ------------------------------------------------
1685             # Only Tag/Value pairs get this far ...
1686             # Either needs to be encrypted, hidden, or both.
1687             # ------------------------------------------------
1688              
1689 6133 50       19848 my $ass = ( is_assign_spaces ( $rOpts ) ) ? "" : $rOpts->{assign};
1690 6133 50       16166 if ( $cmt ) {
1691             DBUG_PRINT ("ENCRYPT", "%s%s %s %s %s %s",
1692 6133         26179 $prefix, $tag, $ass, $mask, $rOpts->{comment}, $cmt);
1693             } else {
1694 0         0 DBUG_PRINT ("ENCRYPT", "%s%s %s %s", $prefix, $tag, $ass, $mask);
1695             }
1696              
1697 6133 100       1632271 unless ( $encrypt ) {
1698 2 50       12 unless (print NEW $line, "\n") {
1699 0         0 return DBUG_RETURN ( croak_helper ($rOpts, $errMsg, 0) );
1700             }
1701 2         13 next;
1702             }
1703              
1704             # --------------------------------------------
1705             # Now let's encrypt the Tag/Value pair ...
1706             # --------------------------------------------
1707              
1708 6131         16048 ++$count;
1709              
1710             # Save the values we need to change safe to use as RegExp strings.
1711 6131         20594 my $old_cmt = convert_to_regexp_string ( $cmt, 1 );
1712 6131         16960 my $old_value = convert_to_regexp_string ( $value, 1 );
1713              
1714             # Modify the label in the comment ...
1715 6131         18577 my $lbl = $rOpts->{decrypt_lbl};
1716 6131         98044 $cmt =~ s/(^|${lbl_sep})${encrypt_str}(${lbl_sep}|$)/$1${lbl}$2/g;
1717              
1718             # Remove any balanced quotes from arround the value ...
1719 6131 100       22258 if ( $lq ) {
1720 27         273 $value =~ s/^${lq}//;
1721 27         222 $value =~ s/${rq}$//;
1722             }
1723              
1724 6131         12642 my ($new_value, $nlq, $nrq);
1725 6131         22531 $new_value = encrypt_value ( $value, $t2, $rOpts, $file);
1726 6131         1582457 ($new_value, $nlq, $nrq) = _apply_escape_sequences ( $new_value, $rOpts );
1727              
1728 6131 50       1814243 if ( is_assign_spaces ( $rOpts ) ) {
1729 0         0 $line =~ s/^(\s*\S+\s+)${old_value}/$1${nlq}${new_value}${nrq}/;
1730             } else {
1731 6131         414090 $line =~ s/(\s*${assign_str}\s*)${old_value}/$1${nlq}${new_value}${nrq}/;
1732             }
1733 6131         77426 $line =~ s/${old_cmt}$/${cmt}/;
1734              
1735 6131 50       95391 unless (print NEW $line, "\n") {
1736 0         0 return DBUG_RETURN ( croak_helper ($rOpts, $errMsg, 0) );
1737             }
1738             } # End the while ENCRYPT loop ...
1739              
1740 7         113 close (ENCRYPT);
1741 7         243 close (NEW);
1742              
1743 7 50       83 my $status = ($count == 0) ? -1 : 1;
1744              
1745 7         60 DBUG_RETURN ( $status );
1746             }
1747              
1748              
1749             # ==============================================================
1750              
1751             =item $status = decrypt_config_file_details ( $file, $writeFile, \%rOpts )
1752              
1753             This function decrypts all tag values inside the specified config file that are
1754             marked as encrypted and generates a new file with everything decrypted. If a
1755             tag/value pair isn't marked as being encrypted it is left alone. By default
1756             this label is B.
1757              
1758             After a tag's value has been decrypted, the label in the comment is updated
1759             from B to B in the config file.
1760              
1761             For this to work, the encryption related options in I<\%rOpts> must match what
1762             was used in the call to I or the decryption will
1763             fail.
1764              
1765             This method ignores any request to source in other config files. You must
1766             decrypt each file individually.
1767              
1768             It writes the results of the decryption process to I<$writeFile>.
1769              
1770             See L for some caveats about this process.
1771              
1772             Returns: B<1> if something was decrypted. B<-1> if nothing was decrypted.
1773             Otherwise B<0> on error.
1774              
1775             =cut
1776              
1777             sub decrypt_config_file_details
1778             {
1779 9     9 1 40 DBUG_ENTER_FUNC ( @_ );
1780 9         4633 my $file = shift;
1781 9         24 my $scratch = shift;
1782 9         22 my $rOpts = shift;
1783              
1784 9         533 unlink ( $scratch );
1785              
1786             # The labels to search for ...
1787 9         61 my $decrypt_str = convert_to_regexp_string ($rOpts->{decrypt_lbl});
1788 9         2190 my $encrypt_str = convert_to_regexp_string ($rOpts->{encrypt_lbl});
1789 9         2177 my $hide_str = convert_to_regexp_string ($rOpts->{hide_lbl});
1790              
1791             # The label separators used when searching for option labels in a comment ...
1792 9         2106 my $lbl_sep = '[\s.,$!-()]';
1793              
1794 9         76 my $assign_str = convert_to_regexp_string ($rOpts->{assign});
1795             my ($lb, $rb) = ( convert_to_regexp_string ($rOpts->{section_left}),
1796 9         2214 convert_to_regexp_string ($rOpts->{section_right}) );
1797              
1798 9         2035 my $mask = "*"x8;
1799              
1800 9         45 DBUG_PRINT ("INFO", "Opening for reading the config file named: %s", $file);
1801              
1802 9 50       2619 unless ( open (DECRYPT, "<", $file) ) {
1803 0         0 return DBUG_RETURN ( croak_helper ($rOpts,
1804             "Unable to open the config file.", 0) );
1805             }
1806              
1807 9         93 DBUG_PRINT ("INFO", "Creating scratch file named: %s", $scratch);
1808 9 50       3326 unless ( open (NEW, ">", $scratch) ) {
1809 0         0 close (DECRYPT);
1810 0         0 return DBUG_RETURN ( croak_helper ($rOpts,
1811             "Unable to create the scratch config file.", 0) );
1812             }
1813              
1814             # Misuse of this option makes the config file unreadable ...
1815 9 100       74 if ( $rOpts->{use_utf8} ) {
1816 1         14 binmode (DECRYPT, "encoding(UTF-8)");
1817 1         73 binmode (NEW, "encoding(UTF-8)");
1818             }
1819              
1820 9         72 my $errMsg = "Unable to write to the scratch file.";
1821              
1822 9         22 my $hide_section = 0;
1823 9         27 my $count = 0;
1824              
1825 9         290 while ( ) {
1826 7410         25235 chomp;
1827 7410         17566 my $line = $_;
1828              
1829 7410         30632 my ($tv, $ln, $cmt, $lq, $rq) = parse_line ( $line, $rOpts );
1830              
1831 7410         2292770 my ($hide, $decrypt) = (0, 0);
1832 7410         20236 my ($tag, $value, $prefix, $t2);
1833 7410 100       29220 if ( $tv ) {
    100          
1834 6682         22019 ($tag, $value, $prefix, $t2) = _split_assign ( $rOpts, $ln );
1835              
1836 6682 100 33     80109 if ( $cmt =~ m/(^|${lbl_sep})${decrypt_str}(${lbl_sep}|$)/ ) {
    50          
1837 6143         16755 ($hide, $decrypt) = (1, 1);
1838              
1839             } elsif ( $cmt =~ m/(^|${lbl_sep})${encrypt_str}(${lbl_sep}|$)/ ||
1840             $cmt =~ m/(^|${lbl_sep})${hide_str}(${lbl_sep}|$)/ ) {
1841 0         0 $hide = 1;
1842              
1843             } else {
1844 539 100 66     2139 if ( $hide_section || should_we_hide_sensitive_data ( $tag, 1 ) ) {
1845 4         10 $hide = 1;
1846             }
1847             }
1848              
1849             # Is it a section whose contents we need to hide???
1850             } elsif ( $ln =~ m/^${lb}\s*(.+?)\s*${rb}$/ ) {
1851 111         609 my $section = lc ($1);
1852 111 50       2959 $hide_section = should_we_hide_sensitive_data ( $section, 1 ) ? 1 : 0;
1853             }
1854              
1855 7410 100       23225 unless ( $hide ) {
1856 1263         5018 DBUG_PRINT ("DECRYPT", $line);
1857 1263 50       298013 unless (print NEW $line, "\n") {
1858 0         0 return DBUG_RETURN ( croak_helper ($rOpts, $errMsg, 0) );
1859             }
1860 1263         8460 next;
1861             }
1862              
1863             # ------------------------------------------------
1864             # Only Tag/Value pairs get this far ...
1865             # Either needs to be decrypted, hidden, or both.
1866             # ------------------------------------------------
1867              
1868 6147 50       19519 my $ass = ( is_assign_spaces ( $rOpts ) ) ? "" : $rOpts->{assign};
1869 6147 100       18979 if ( $decrypt ) {
    50          
1870 6143         26524 DBUG_PRINT ("DECRYPT", $line);
1871             } elsif ( $cmt ) {
1872             DBUG_PRINT ("DECRYPT", "%s%s %s %s %s %s",
1873 4         21 $prefix, $tag, $ass, $mask, $rOpts->{comment}, $cmt);
1874             } else {
1875 0         0 DBUG_PRINT ("DECRYPT", "%s%s %s %s", $prefix, $tag, $ass, $mask);
1876             }
1877              
1878 6147 100       1507481 unless ( $decrypt ) {
1879 4 50       23 unless (print NEW $line, "\n") {
1880 0         0 return DBUG_RETURN ( croak_helper ($rOpts, $errMsg, 0) );
1881             }
1882 4         26 next;
1883             }
1884              
1885             # --------------------------------------------
1886             # Now let's decrypt the tag/value pair ...
1887             # --------------------------------------------
1888              
1889 6143         16135 ++$count;
1890              
1891             # Save the values we need to change safe to use as RegExp strings.
1892 6143         21270 my $old_cmt = convert_to_regexp_string ( $cmt, 1 );
1893 6143         18178 my $old_value = convert_to_regexp_string ( $value, 1 );
1894              
1895             # Modify the label in the comment ...
1896 6143         20388 my $lbl = $rOpts->{encrypt_lbl};
1897 6143         87416 $cmt =~ s/(^|${lbl_sep})${decrypt_str}(${lbl_sep}|$)/$1${lbl}$2/g;
1898              
1899             # Remove any balanced quotes from arround the value ...
1900 6143 50       22568 if ( $lq ) {
1901 6143         40290 $value =~ s/^${lq}//;
1902 6143         46657 $value =~ s/${rq}$//;
1903             }
1904              
1905 6143         27514 my ($new_value, $nlq, $nrq, $rlq2, $rrq2) = _reverse_escape_sequences ( $value, $rOpts );
1906 6143         1961956 $new_value = decrypt_value ( $new_value, $t2, $rOpts, $file);
1907              
1908 6143 50       1605100 if ( $nlq ) {
1909 6143 100 66     84420 if ( $new_value =~ m/${rlq2}/ || $new_value =~ m/${rrq2}/ ) {
1910 13         48 $nlq = $nrq = ""; # Balanced quotes are not supported for this value!
1911             }
1912             }
1913              
1914 6143 50       29381 if ( is_assign_spaces ( $rOpts ) ) {
1915 0         0 $line =~ s/^(\s*\S+\s+)${old_value}/$1${nlq}${new_value}${nrq}/;
1916             } else {
1917 6143         458434 $line =~ s/(\s*${assign_str}\s*)${old_value}/$1${nlq}${new_value}${nrq}/;
1918             }
1919 6143         83730 $line =~ s/${old_cmt}$/${cmt}/;
1920              
1921 6143 50       99720 unless (print NEW $line, "\n") {
1922 0         0 return DBUG_RETURN ( croak_helper ($rOpts, $errMsg, 0) );
1923             }
1924             } # End the while ENCRYPT loop ...
1925              
1926 9         35 close (ENCRYPT);
1927 9         402 close (NEW);
1928              
1929 9 50       85 my $status = ($count == 0) ? -1 : 1;
1930              
1931 9         63 DBUG_RETURN ( $status );
1932             }
1933              
1934              
1935             # ==============================================================
1936              
1937             =item $value = encrypt_value ($value, $tag, $rOpts, $file)
1938              
1939             Takes the I<$value> and encrypts it using the other B<3> args as part of the
1940             encryption key. To successfully decrypt it again you must pass the same B<3>
1941             values for these args to the I call.
1942              
1943             See L for some caveats about this process.
1944              
1945             =cut
1946              
1947             sub encrypt_value
1948             {
1949 6131     6131 1 23890 DBUG_MASK_NEXT_FUNC_CALL (0); # Masks ${value} ...
1950 6131         264895 DBUG_ENTER_FUNC ( @_ );
1951 6131         3688295 my $value = shift; # In clear text ...
1952 6131         13284 my $tag = shift;
1953 6131         10771 my $rOpts = shift;
1954 6131         11426 my $file = shift;
1955              
1956             # Using the file or the alias?
1957 6131 100       394577 my $alias = basename ( ( $rOpts->{alias} ) ? $rOpts->{alias} : $file );
1958              
1959             # ---------------------------------------------------------------
1960             # Call the custom encryption call back method ...
1961             # ---------------------------------------------------------------
1962 6131 50 33     56534 if ( exists $rOpts->{encrypt_cb} && ref ( $rOpts->{encrypt_cb} ) eq "CODE" ) {
1963 6131         35001 $value = $rOpts->{encrypt_cb}->( 1, $tag, $value, $alias, $rOpts->{encrypt_cb_opts} );
1964             }
1965              
1966             # ---------------------------------------------------------------
1967             # Pad the value out to a minimum lenth ...
1968             # ---------------------------------------------------------------
1969 6131         1687001 my $len1 = length ($value);
1970 6131         15933 my $len2 = length ($tag);
1971 6131 100       19122 my $len = ($len1 > $len2) ? $len1 : $len2;
1972 6131         16980 my $len3 = length ($rOpts->{pass_phrase});
1973 6131 50       16218 $len = ( $len > $len3) ? $len : $len3;
1974              
1975             # Enforce a minimum length for the value ... (will always end in spaces)
1976 6131 100       19758 $len = ($len < 12) ? 15 : ($len + 3);
1977 6131         34527 $value = sprintf ("%-*s", $len, $value . "|");
1978              
1979             # ---------------------------------------------------------------
1980             # Encrypt the value via this module ...
1981             # ---------------------------------------------------------------
1982 6131         29131 $value = _encrypt ( $value, $rOpts->{pass_phrase}, $tag, $alias, $rOpts->{encrypt_by_user} );
1983              
1984 6131         1649710 DBUG_RETURN ( $value );
1985             }
1986              
1987             # ==============================================================
1988              
1989             =item $value = decrypt_value ($value, $tag, $rOpts, $file)
1990              
1991             Takes the I<$value> and decrypts it using the other B<3> args as part of the
1992             decryption key. To successfully decrypt it the values for these B<3> args
1993             must match what was passed to I when the value was
1994             originally encrypted.
1995              
1996             See L for some caveats about this process.
1997              
1998             =cut
1999              
2000             sub decrypt_value
2001             {
2002 12353     12353 1 50612 DBUG_ENTER_FUNC ( @_ );
2003 12353         4647616 my $value = shift; # It's encrypted ...
2004 12353         26034 my $tag = shift;
2005 12353         21771 my $rOpts = shift;
2006 12353         21430 my $file = shift;
2007              
2008 12353         52628 DBUG_MASK (0); # Mask the return value ... It's sensitive by definition!
2009              
2010             # Using the file or the alias?
2011 12353 100       1180779 my $alias = basename ( ( $rOpts->{alias} ) ? $rOpts->{alias} : $file );
2012              
2013             # ---------------------------------------------------------------
2014             # Decrypt the value via this module ...
2015             # ---------------------------------------------------------------
2016 12353         64714 $value = _encrypt ( $value, $rOpts->{pass_phrase}, $tag, $alias, $rOpts->{encrypt_by_user} );
2017 12353         2388022 $value =~ s/\|[\s\0]+$//; # Trim any trailing spaces or NULL chars.
2018              
2019             # ---------------------------------------------------------------
2020             # Call the custom decryption call back method ...
2021             # ---------------------------------------------------------------
2022 12353 50 33     109418 if ( exists $rOpts->{encrypt_cb} && ref ( $rOpts->{encrypt_cb} ) eq "CODE" ) {
2023 12353         65055 $value = $rOpts->{encrypt_cb}->( 0, $tag, $value, $alias, $rOpts->{encrypt_cb_opts} );
2024             }
2025              
2026 12353         2383736 DBUG_RETURN ( $value );
2027             }
2028              
2029              
2030             # ==============================================================
2031             # Before writing an encrypted value to a config file, all problem
2032             # character sequences must be converted into escape sequences. So
2033             # that when the encrypted value is read back in again it won't cause
2034             # parsing issues.
2035             sub _apply_escape_sequences
2036             {
2037 6131     6131   24383 DBUG_ENTER_FUNC ( @_ );
2038 6131         3411734 my $value = shift; # Encrypted ...
2039 6131         15305 my $rOpts = shift;
2040              
2041 6131         19639 my ( $lq, $rq ) = _get_encryption_quotes ( $rOpts );
2042              
2043             # Strings to use in the regular expressions ...
2044 6131         24033 my ($l_quote, $r_quote) = ( convert_to_regexp_string ($lq, 1),
2045             convert_to_regexp_string ($rq, 1) );
2046 6131         23934 my $cmt = convert_to_regexp_string ($rOpts->{comment}, 1);
2047 6131         25016 my $var = convert_to_regexp_string ($rOpts->{variable_left}, 1);
2048              
2049             # ---------------------------------------------------------------
2050             # Replace any problem char for values with escape sequences ...
2051             # ---------------------------------------------------------------
2052 6131         19715 $value =~ s/\\/\\z/sg; # Done so we can use \ as an escape sequence.
2053 6131         19091 $value =~ s/\n/\\n/sg; # Remove embedded "\n" so no mult-lines.
2054 6131         14085 $value =~ s/%/\\p/sg; # So calls to DBUG_PRINT won't barf ...
2055 6131         30427 $value =~ s/${cmt}/\\3/sg; # Don't want any comment chars ...
2056 6131 50       17863 if ( $rq ) {
2057 6131         21391 $value =~ s/${l_quote}/\\q/sg;
2058 6131         20138 $value =~ s/${r_quote}/\\Q/sg;
2059             }
2060 6131         17574 $value =~ s/${var}/\\v/sg; # So nothing looks like a variable ...
2061 6131         15417 $value =~ s/\0/\\0/sg; # So no embedded null chars ...
2062              
2063 6131         20371 DBUG_RETURN ( $value, $lq, $rq );
2064             }
2065              
2066              
2067             # ==============================================================
2068             # When an encrypted value is read in from the config file, all escape
2069             # secuences need to be removed before the value can be decrypted.
2070             # These escape sequences were required to avoid parsing issues when
2071             # handling encrypted values.
2072             sub _reverse_escape_sequences
2073             {
2074 12367     12367   52420 DBUG_ENTER_FUNC ( @_ );
2075 12367         4564931 my $value = shift; # Encrypted with escape sequences ...
2076 12367         26279 my $rOpts = shift;
2077              
2078 12367         44727 my ( $lq, $rq ) = _get_encryption_quotes ( $rOpts );
2079 12367         35897 my $cmt = $rOpts->{comment};
2080 12367         31421 my $var = $rOpts->{variable_left};
2081              
2082             # Strings to use in the regular expressions ... (by caller)
2083 12367         41506 my ($l_quote, $r_quote) = ( convert_to_regexp_string ($lq, 1),
2084             convert_to_regexp_string ($rq, 1) );
2085              
2086             # ---------------------------------------------------------------
2087             # Replace the escape sequences to get back the problem chars ...
2088             # Done in reverse order of what was done in: _apply_escape_sequences()!
2089             # ---------------------------------------------------------------
2090 12367         47509 $value =~ s/\\0/\0/sg;
2091 12367         40551 $value =~ s/\\v/${var}/sg;
2092 12367 50       31843 if ( $rq ) {
2093 12367         29744 $value =~ s/\\Q/${rq}/sg;
2094 12367         29060 $value =~ s/\\q/${lq}/sg;
2095             }
2096 12367         28281 $value =~ s/\\3/${cmt}/sg;
2097 12367         29666 $value =~ s/\\p/%/sg;
2098 12367         35955 $value =~ s/\\n/\n/sg;
2099 12367         30628 $value =~ s/\\z/\\/sg;
2100              
2101 12367         44075 DBUG_RETURN ( $value, $lq, $rq, $l_quote, $r_quote );
2102             }
2103              
2104              
2105             # ==============================================================
2106             sub _get_encryption_quotes
2107             {
2108 18498     18498   35050 my $rOpts = shift;
2109              
2110 18498         52229 my ($lq, $rq) = ("", "");
2111 18498 100       62981 if ( using_default_quotes ( $rOpts ) ) {
    50          
2112 18448         4124793 $lq = $rq = "'"; # Chooses ' over " ...
2113             } elsif ( ! $rOpts->{disable_quotes} ) {
2114 50         13376 ($lq, $rq) = ( $rOpts->{quote_left}, $rOpts->{quote_right} );
2115             }
2116              
2117 18498         73424 return ( $lq, $rq );
2118             }
2119              
2120              
2121             # ==============================================================
2122             # USAGE: $val = _encrypt ($value, $pass_code, $tag, $alias, $usr_flg)
2123             #
2124             # Both encrypts & decrypts the value ...
2125              
2126             sub _encrypt
2127             {
2128 18484     18484   67410 DBUG_MASK_NEXT_FUNC_CALL (0, 1); # Masks ${val} & ${pass} ...
2129 18484         956404 DBUG_ENTER_FUNC ( @_ );
2130 18484         8941827 my $val = shift; # Sensitive ... if not already encrypted.
2131 18484         42810 my $pass = shift; # Very, very sensitive ... always clear text.
2132 18484         44540 my $tag = shift;
2133 18484         36144 my $alias = shift;
2134 18484         30393 my $usr_flg = shift; # 0 - no, 1 - yes
2135 18484         69320 DBUG_MASK (0);
2136              
2137             # Verify lengths are different to prevent repeatable patterns.
2138 18484 50       694500 if ( length ( $tag ) == length ( $alias ) ) {
2139 0         0 $tag .= "|"; # Make different lengths
2140             }
2141              
2142 18484         55470 my $len = length ( $val );
2143              
2144 18484         61436 my $key1 = _make_key ( $tag, $len );
2145 18484         4265176 my $key2 = _make_key ( $alias, $len );
2146 18484         4144906 my $res = $key1 ^ $key2;
2147              
2148 18484 50       61547 if ( $pass ) {
2149 0         0 my $key3 = _make_key ( $pass, $len );
2150 0         0 $res = $res ^ $key3;
2151             }
2152              
2153 18484 50       48278 if ( $usr_flg ) {
2154 0         0 my $key4 = _make_key ( $gUserName, $len );
2155 0         0 $res = $res ^ $key4;
2156             }
2157              
2158 18484 100       89212 unless ( $val =~ m/[^\x00-\xff]/ ) {
2159 15448         45396 $res = $res ^ $val; # ascii ...
2160             } else {
2161             # Unicode version of ($res ^ $val) ...
2162 3036         11128 $res = _bitwise_exclusive_or ( $res, $val );
2163             }
2164              
2165 18484         726336 DBUG_RETURN ( $res ); # Sometimes encrypted and other times not!
2166             }
2167              
2168             # ==============================================================
2169             sub _bitwise_exclusive_or
2170             {
2171 3036     3036   10865 DBUG_ENTER_FUNC (); # Dropped @_ on purpose, always sensitive
2172 3036         707025 my $mask = shift;
2173 3036         7200 my $unicode = shift;
2174 3036         11878 DBUG_MASK (0);
2175              
2176 3036         106897 my @m = unpack ("C*", $mask);
2177 3036         14498 my @u = unpack ("U*", $unicode);
2178              
2179 3036         7626 my @ans;
2180 3036         18521 foreach ( 0..$#u ) {
2181 46632         87873 $ans[$_] = $m[$_] ^ $u[$_]; # Exclusive or of 2 integers still supported.
2182             }
2183              
2184 3036         21481 DBUG_RETURN ( pack ("U*", @ans) );
2185             }
2186              
2187             # ==============================================================
2188             # USAGE: $key = _make_key ($target, $len);
2189              
2190             sub _make_key
2191             {
2192 36968     36968   126466 DBUG_MASK_NEXT_FUNC_CALL (0); # Masks ${target} ...
2193 36968         1447249 DBUG_ENTER_FUNC ( @_ );
2194 36968         17379627 my $target = shift; # May be ascii or unicode ...
2195 36968         72839 my $len = shift;
2196 36968         119463 DBUG_MASK (0);
2197              
2198 36968         1246311 my $phrase;
2199 36968 100       142449 unless ( $target =~ m/[^\x00-\xff]/ ) {
2200             # Normal text ... (ascii)
2201 36926         279134 $phrase = $target . pack ("C*", reverse (unpack ("C*", $target)));
2202              
2203             } else {
2204             # Unicode strings (utf8 / Wide Chars)
2205             # Strip off the upper byte from each unicode char ...
2206 42         316 my @ans = map { $_ % 0x100 } unpack ("U*", $target);
  207         447  
2207 42         314 $phrase = pack ("C*", @ans) . pack ("C*", reverse (@ans));
2208             }
2209              
2210 36968         107966 my $key = $phrase;
2211 36968         124446 while ( length ( $key ) < $len ) {
2212 12172         49976 $key .= $phrase;
2213             }
2214              
2215 36968         108909 $key = substr ( $key, 0, $len ); # Truncate it to fit ...
2216              
2217 36968         109032 DBUG_RETURN ( $key ); # Always an ascii string ...
2218             }
2219              
2220             # ==============================================================
2221              
2222             =back
2223              
2224             =head1 COPYRIGHT
2225              
2226             Copyright (c) 2007 - 2026 Curtis Leach. All rights reserved.
2227              
2228             This program is free software. You can redistribute it and/or modify it under
2229             the same terms as Perl itself.
2230              
2231             =head1 SEE ALSO
2232              
2233             L - The main user of this module. It defines the Config object.
2234              
2235             L - Handles the configuration of the Config module.
2236              
2237             L - Handles date parsing for get_date().
2238              
2239             L - Provides some sample config files and commentary.
2240              
2241             =cut
2242              
2243             # ==============================================================
2244             #required if module is included w/ require command;
2245             1;
2246