@@ -47,6 +47,7 @@ our @EXPORT_OK = qw/change_seconds
4747 slurp_file
4848 format_opt
4949 trim
50+ mask_secrets
5051 value_of/ ;
5152
5253sub execute {
@@ -192,13 +193,19 @@ sub unix_execute {
192193 # On some equipment. Cannot get a pseudo terminal
193194 if (defined ($options {ssh_pipe }) && $options {ssh_pipe } == 1) {
194195 $cmd = " echo '" . $sub_cmd . " ' | " . $cmd . ' ' . join (' ' , @$args );
196+ $options {output }-> output_add(long_msg => ' execute command: ' . $cmd , show_password => $options {output }-> show_password()) if $options {output }-> is_debug();
197+
195198 ($lerror , $stdout , $exit_code ) = backtick(
196199 command => $cmd ,
197200 timeout => $options {options }-> {timeout },
198201 wait_exit => $wait_exit ,
199202 redirect_stderr => $redirect_stderr
200203 );
201204 } else {
205+ if ($options {output }-> is_debug()) {
206+ my $cmd = $cmd . join (' ' , [ @$args , $sub_cmd // ' ' ]);
207+ $options {output }-> output_add(long_msg => ' execute command: ' . $cmd , show_password => $options {output }-> show_password())
208+ }
202209 ($lerror , $stdout , $exit_code ) = backtick(
203210 command => $cmd ,
204211 arguments => [@$args , $sub_cmd ],
@@ -213,6 +220,8 @@ sub unix_execute {
213220 $cmd .= $options {command } if (defined ($options {command }));
214221 $cmd .= ' ' . $options {command_options } if (defined ($options {command_options }));
215222
223+ $options {output }-> output_add(long_msg => ' execute command: ' . $cmd , show_password => $options {output }-> show_password()) if $options {output }-> is_debug();
224+
216225 if (defined ($options {no_shell_interpretation }) and $options {no_shell_interpretation } ne ' ' ) {
217226 my @args = split (' ' ,$cmd );
218227 ($lerror , $stdout , $exit_code ) = backtick(
@@ -961,6 +970,68 @@ sub format_opt($) {
961970 $_ [0] =~ s / _/ -/ gr ;
962971}
963972
973+ # Attempts to mask secrets in a command line string by replacing them with $mask ( or *** if mask is not defined )
974+ # Be aware that this is only a try, there is no guarantee that all secrets will be masked!
975+ sub mask_secrets ($;$) {
976+ my ($command , $mask ) = @_ ;
977+
978+ return ' ' unless $command ;
979+
980+ $mask = ' ***' unless defined $mask ;
981+
982+ my $masked = $command ;
983+
984+ # Handled cases with examples
985+
986+ # command -password P@s$W@rD -I100
987+ $masked =~ s / (\s +-+password[=\s :]+)[^\s '"]+/ $1 $mask / gi ;
988+
989+ # command -token=P@s$W@rD -I100
990+ $masked =~ s / (\s +-+token[=\s :]+)[^\s '"]+/ $1 $mask / gi ;
991+
992+ # curl --header "api-key: P@s$W@rD" https://test.com' OR curl -api-key P@s$W@rD
993+ $masked =~ s / (\s +-+api[_-]?key[=\s :]+)[^\s '"]+/ $1 $mask / gi ;
994+ $masked =~ s / (api[_-]?key\s *:\s *)[^\s '"]+/ $1 $mask / gi ;
995+
996+ # command -secret=P@s$W@rD -I100
997+ $masked =~ s / (\s +-+secret[=\s :]+)[^\s '"]+/ $1 $mask / gi ;
998+
999+ # curl --header "secret: P@s$W@rD" https://test.com'
1000+ $masked =~ s / (secret\s *:\s *)[^\s '"]+/ $1 $mask / gi ;
1001+
1002+ # command -authent=P@s$W@rD -I100
1003+ $masked =~ s / (\s +-+auth(ent)?[=\s :]+)[^\s '"]+/ $1 $mask / gi ;
1004+
1005+ # command -cert-password=P@s$W@rD -I100
1006+ $masked =~ s / (\s +-+cert[_-]?password[=\s :]+)[^\s '"]+/ $1 $mask / gi ;
1007+ # command -passphrase=P@s$W@rD -I100
1008+ $masked =~ s / (\s +-+passphrase[=\s :]+)[^\s '"]+/ $1 $mask / gi ;
1009+
1010+ # snmpwalk -snmp-community MyCommunitString123 -v 2c localhost',
1011+ $masked =~ s / (\s +-+snmp[_-]?community[=\s :]+)[^\s '"]+/ $1 $mask / gi ;
1012+
1013+ # snmpwalk --c MyCommunitString123 -v 2c localhost',
1014+ $masked =~ s / (\s -c\s +)[^\s '"]+/ $1 $mask / gi ;
1015+
1016+ # mysql -u root -p PASSWORD database
1017+ $masked =~ s / (\s +-p\s +)[^\s '"]+/ $1 $mask / gi ;
1018+
1019+ # mysql -u root -pPASSWORD database
1020+ $masked =~ s / (\s +-p)(?!assword\b )([A-Z])[^\s '"]*/ $1 $mask / gi ;
1021+
1022+ my $common_auth = ' Bearer|Basic|Negotiate|X-API-Key|ApiKey|NTLM|AWS4-HMAC-SHA256' ;
1023+
1024+ # curl -H "Authorization: Bearer ABCDEF" http://test.com'
1025+ $masked =~ s / ((?:$common_auth)\s +)[^\s '"]+/ $1 $mask / gi ;
1026+ # curl -H "PVX-Authorization: ABCDEF" http://test.com'
1027+ $masked =~ s / ((?:[\w -]*)Authorization\s *:\s *)(?!$common_auth)[^\s ',;"]+/ $1 $mask / gi ;
1028+
1029+ # https://admin:password@test.com:8080/api
1030+ $masked =~ s / ([\w .-]+):([\w ?!@#$%^&*._-]+)(@)/ $1 :$mask$3 / g ;
1031+
1032+ return $masked ;
1033+ }
1034+
96410351;
9651036
9661037__END__
@@ -1616,6 +1687,19 @@ Returns 1 if the string is excluded, 0 if it is included.
16161687The string is excluded if $exclude_regexp is defined and matches the string, or if $include_regexp is defined and does
16171688not match the string. The string will also be excluded if it is undefined.
16181689
1690+ =back
1691+
1692+ =head2 mask_secrets
1693+
1694+ my $to_print = centreon::plugins::misc::mask_secrets($unsafe_string, $mask);
1695+
1696+ Attempts to mask secrets in a command line string by replacing them with $mask ( or *** if mask is not defined )
1697+ Be aware that this is only a try, there is no guarantee that all secrets will be masked!
1698+
1699+ =over 4
1700+
1701+ =item * C<$ident > - name to convert.
1702+
16191703=head1 AUTHOR
16201704
16211705Centreon
0 commit comments