You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spamassassin.apache.org by he...@apache.org on 2019/08/12 09:12:40 UTC

svn commit: r1864949 - in /spamassassin/trunk: UPGRADE lib/Mail/SpamAssassin/Logger.pm lib/Mail/SpamAssassin/Logger/File.pm lib/Mail/SpamAssassin/Logger/Stderr.pm lib/Mail/SpamAssassin/Logger/Syslog.pm spamd/spamd.raw

Author: hege
Date: Mon Aug 12 09:12:40 2019
New Revision: 1864949

URL: http://svn.apache.org/viewvc?rev=1864949&view=rev
Log:
- Bug 6583: Add new escape option to Logger::add() and Logger/*.pm modules and start using it
- Fix duplicate log supressor logic to escape duplicated message properly

Modified:
    spamassassin/trunk/UPGRADE
    spamassassin/trunk/lib/Mail/SpamAssassin/Logger.pm
    spamassassin/trunk/lib/Mail/SpamAssassin/Logger/File.pm
    spamassassin/trunk/lib/Mail/SpamAssassin/Logger/Stderr.pm
    spamassassin/trunk/lib/Mail/SpamAssassin/Logger/Syslog.pm
    spamassassin/trunk/spamd/spamd.raw

Modified: spamassassin/trunk/UPGRADE
URL: http://svn.apache.org/viewvc/spamassassin/trunk/UPGRADE?rev=1864949&r1=1864948&r2=1864949&view=diff
==============================================================================
--- spamassassin/trunk/UPGRADE (original)
+++ spamassassin/trunk/UPGRADE Mon Aug 12 09:12:40 2019
@@ -2,6 +2,12 @@
 Note for Users Upgrading to SpamAssassin 4.0.0
 ----------------------------------------------
 
+- All log output (stderr, file, syslog) is now binary safe,
+  non-ascii characters are escaped as \x{XX} or \x{XXXX}, backslashes escaped
+  as \\. Whitespace is not normalized anymore like in pre-4.0 versions.
+
+- API: Logger::add() has new optional 'escape' parameter.
+
 - API: New $pms->add_uri_detail_list() function.  Also new uri_detail_list
   types: unlinked, schemeless
 

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Logger.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Logger.pm?rev=1864949&r1=1864948&r2=1864949&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Logger.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Logger.pm Mon Aug 12 09:12:40 2019
@@ -74,7 +74,8 @@ $LOG_SA{facility} = {};		# no dbg facili
 
 # always log to stderr initially
 use Mail::SpamAssassin::Logger::Stderr;
-$LOG_SA{method}->{stderr} = Mail::SpamAssassin::Logger::Stderr->new();
+$LOG_SA{method}->{stderr} =
+  Mail::SpamAssassin::Logger::Stderr->new(escape => 1);
 
 =head1 METHODS
 
@@ -164,7 +165,7 @@ sub log_message {
     # don't log them -- this is caller 0, the use'ing package is 1, the eval is 2
     my @caller = caller 2;
     return if (defined $caller[3] && defined $caller[0] &&
-		       $caller[3] =~ /^\(eval\)$/ &&
+		       $caller[3] eq '(eval)' &&
 		       $caller[0] =~ m#^Mail::SpamAssassin(?:$|::)#);
   }
 
@@ -188,33 +189,44 @@ sub log_message {
   } else {
     if ($LOG_DUPCNT >= $LOG_DUPMIN) {
       $LOG_DUPCNT -= $LOG_DUPMIN - 1;
-      my $dupmsg = $LOG_DUPCNT > 1 ? " [... logline repeated $LOG_DUPCNT times]" : "";
-      while (my ($name, $object) = each %{ $LOG_SA{method} }) {
-        $object->log_message($level, "$LOG_DUPLINE$dupmsg", $LOG_DUPTIME);
+      if ($LOG_DUPCNT > 1) {
+        _log_message($level,
+                     "$LOG_DUPLINE [... logline repeated $LOG_DUPCNT times]",
+                     $LOG_DUPTIME);
+      } else {
+        _log_message($level, $LOG_DUPLINE, $LOG_DUPTIME);
       }
     }
     $LOG_DUPCNT = 0;
     $LOG_DUPLINE = $message;
   }
 
+  _log_message($level, $message, $now);
+
+  $LOG_ENTERED = 0;
+}
+
+# Private helper
+sub _log_message {
   # split on newlines and call log_message multiple times; saves
   # the subclasses having to understand multi-line logs
   my $first = 1;
-  foreach my $line (split(/\n/, $message)) {
+  foreach my $line (split(/\n/, $_[1])) {
     # replace control characters with "_", tabs and spaces get
     # replaced with a single space.
-    $line =~ tr/\x09\x20\x00-\x1f/  _/s;
+    # Deprecated here, see new Bug 7305 escaping in Logger/*.pm modules
+    #$line =~ tr/\x09\x20\x00-\x1f/  _/s;
+
     if ($first) {
       $first = 0;
     } else {
-      local $1;
       $line =~ s/^([^:]+?):/$1: [...]/;
     }
+
     while (my ($name, $object) = each %{ $LOG_SA{method} }) {
-      $object->log_message($level, $line, $now);
+      $object->log_message($_[0], $line, $_[2]);
     }
   }
-  $LOG_ENTERED = 0;
 }
 
 =item dbg("facility: message")
@@ -273,18 +285,27 @@ sub _log {
   log_message(($level == INFO ? "info" : "dbg"), $message);
 }
 
-=item add(method => 'syslog', socket => $socket, facility => $facility)
+=item add(method => 'syslog', socket => $socket, facility => $facility, escape => $escape)
 
 C<socket> is the type the syslog ("unix" or "inet").  C<facility> is the
-syslog facility (typically "mail").
+syslog facility (typically "mail").  If optional C<escape> is true, all
+non-ascii characters are escaped for safe output.  If C<escape> is not
+defined, pre-4.0 style sanitizing is used.
+
+=item add(method => 'file', filename => $file, escape => $escape)
 
-=item add(method => 'file', filename => $file)
+C<filename> is the name of the log file.  If optional C<escape> is true,
+escape all non-ascii characters are escaped for safe output.  If C<escape>
+is not defined, pre-4.0 style sanitizing is used.
 
-C<filename> is the name of the log file.
+=item add(method => 'stderr', escape => $escape)
 
-=item add(method => 'stderr')
+No options are needed for stderr logging, just don't close stderr first.  If
+optional C<escape> is true, all non-ascii characters are escaped for safe
+output.  If C<escape> is not defined, pre-4.0 style sanitizing is used.
 
-No options are needed for stderr logging, just don't close stderr first.
+Escape method changes backslashes to \\ and non-ascii chars to \x{XX} or
+\x{XXXX} (Unicode).  Pre-4.0 style is tr/\x09\x20\x00-\x1f/ _/s.
 
 =cut
 

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Logger/File.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Logger/File.pm?rev=1864949&r1=1864948&r2=1864949&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Logger/File.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Logger/File.pm Mon Aug 12 09:12:40 2019
@@ -58,6 +58,7 @@ sub new {
   my %params = @_;
   $self->{filename} = $params{filename} || 'spamassassin.log';
   $self->{timestamp_fmt} = $params{timestamp_fmt};
+  $self->{escape} = $params{escape} if exists $params{escape};
 
   if (! $self->init()) {
     die "logger: file initialization failed$eol";
@@ -101,6 +102,20 @@ sub log_message {
   }
   $timestamp .= ' '  if $timestamp ne '';
 
+  if ($self->{escape}) {
+    local $1;
+    # Bug 7305:
+    # Quote non-ascii characters as \x{XX} or \x{XXXX} (Unicode)
+    # Also quote backslash, so the log can be unescaped properly
+    $msg =~ s{([^\x20-\x5b\x5d-\x7e])}{ $1 eq '\\' ? '\\\\' :
+      sprintf(ord($1) > 255 ? '\\x{%04X}' : '\\x{%02X}', ord($1)) }egs;
+  } elsif (!exists $self->{escape}) {
+    # Backwards compatible pre-4.0 escaping, if $escape not given.
+    # replace control characters with "_", tabs and spaces get
+    # replaced with a single space.
+    $msg =~ tr/\x09\x20\x00-\x1f/  _/s;
+  }
+
   my($nwrite) = syswrite(STDLOG, sprintf("%s[%s] %s: %s%s",
                                          $timestamp, $$, $level, $msg, $eol));
   defined $nwrite  or warn "error writing to log file: $!";

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Logger/Stderr.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Logger/Stderr.pm?rev=1864949&r1=1864948&r2=1864949&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Logger/Stderr.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Logger/Stderr.pm Mon Aug 12 09:12:40 2019
@@ -59,6 +59,7 @@ sub new {
 
   my %params = @_;
   $self->{timestamp_fmt} = $params{timestamp_fmt};
+  $self->{escape} = $params{escape} if exists $params{escape};
 
   return($self);
 }
@@ -83,6 +84,20 @@ sub log_message {
   }
   $timestamp .= ' '  if $timestamp ne '';
 
+  if ($self->{escape}) {
+    local $1;
+    # Bug 7305:
+    # Quote non-ascii characters as \x{XX} or \x{XXXX} (Unicode)
+    # Also quote backslash, so the log can be unescaped properly
+    $msg =~ s{([^\x20-\x5b\x5d-\x7e])}{ $1 eq '\\' ? '\\\\' :
+      sprintf(ord($1) > 255 ? '\\x{%04X}' : '\\x{%02X}', ord($1)) }egs;
+  } elsif (!exists $self->{escape}) {
+    # Backwards compatible pre-4.0 escaping, if $escape not given.
+    # replace control characters with "_", tabs and spaces get
+    # replaced with a single space.
+    $msg =~ tr/\x09\x20\x00-\x1f/  _/s;
+  }
+
   my($nwrite) = syswrite(STDERR, sprintf("%s[%d] %s: %s%s",
                                          $timestamp, $$, $level, $msg, $eol));
   defined $nwrite  or warn "error writing to log file: $!";

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Logger/Syslog.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Logger/Syslog.pm?rev=1864949&r1=1864948&r2=1864949&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Logger/Syslog.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Logger/Syslog.pm Mon Aug 12 09:12:40 2019
@@ -73,6 +73,7 @@ sub new {
   $self->{log_socket} = $params{socket};
   $self->{log_facility} = $params{facility};
   $self->{timestamp_fmt} = $params{timestamp_fmt};
+  $self->{escape} = $params{escape} if exists $params{escape};
 
   if (! $self->init()) {
     die "logger: syslog initialization failed\n";
@@ -148,6 +149,20 @@ sub log_message {
     $msg = '(bad prio: ' . $_[1] . ') ' . $msg;
   }
 
+  if ($self->{escape}) {
+    local $1;
+    # Bug 7305:
+    # Quote non-ascii characters as \x{XX} or \x{XXXX} (Unicode)
+    # Also quote backslash, so the log can be unescaped properly
+    $msg =~ s{([^\x20-\x5b\x5d-\x7e])}{ $1 eq '\\' ? '\\\\' :
+      sprintf(ord($1) > 255 ? '\\x{%04X}' : '\\x{%02X}', ord($1)) }egs;
+  } elsif (!exists $self->{escape}) {
+    # Backwards compatible pre-4.0 escaping, if $escape not given
+    # replace control characters with "_", tabs and spaces get
+    # replaced with a single space.
+    $msg =~ tr/\x09\x20\x00-\x1f/  _/s;
+  }
+
   # install a new handler for SIGPIPE -- this signal has been
   # found to occur with syslog-ng after syslog-ng restarts.
   local $SIG{'PIPE'} = sub {

Modified: spamassassin/trunk/spamd/spamd.raw
URL: http://svn.apache.org/viewvc/spamassassin/trunk/spamd/spamd.raw?rev=1864949&r1=1864948&r2=1864949&view=diff
==============================================================================
--- spamassassin/trunk/spamd/spamd.raw (original)
+++ spamassassin/trunk/spamd/spamd.raw Mon Aug 12 09:12:40 2019
@@ -462,7 +462,8 @@ if (defined $log_timestamp_fmt) {
   # a nondefault timestamp format was specified, need to reopen stderr logger
   Mail::SpamAssassin::Logger::remove('stderr');
   Mail::SpamAssassin::Logger::add(method => 'stderr',
-				  timestamp_fmt => $log_timestamp_fmt);
+				  timestamp_fmt => $log_timestamp_fmt,
+				  escape => 1);
 }
 
 # Enable debugging, if any areas were specified.  We do this already here,
@@ -602,7 +603,8 @@ if ($log_socket ne 'file' && $log_facili
 				       socket => $log_socket,
 				       facility => $log_facility,
 				       ident => 'spamd',
-				       timestamp_fmt => $log_timestamp_fmt))
+				       timestamp_fmt => $log_timestamp_fmt,
+				       escape => 1))
   {
     # syslog method failed 
     $log_facility = 'stderr';
@@ -612,7 +614,8 @@ if ($log_socket ne 'file' && $log_facili
 elsif ($log_facility eq 'file') {
   if (!Mail::SpamAssassin::Logger::add(method => 'file',
 				       filename => $log_file,
-				       timestamp_fmt => $log_timestamp_fmt))
+				       timestamp_fmt => $log_timestamp_fmt,
+				       escape => 1))
   {
     # file method failed
     $log_facility = 'stderr';