Package: libmail-audit-perl
Version: 2.1-5sarge2
Tags: patch

The libmail-audit-perl 2.1-5sarge2 NMU update tries to fix the insecure temporary file creation bug in Mail::Audit. However, the fix can cause serious problems in cases where $ENV{HOME} is not set.

The problem is with this line at the top:

  (undef,$logfile) = tempfile("mail_audit.log-XXXXX",TMPDIR=>1);

The first problem with this is that "TMPDIR=>1" is not a valid option for File::Temp's "tempfile" -- that option only works with tempdir(). So that option is being ignored and the temporary file is being created in the current working directory instead, which fails if the program doesn't have write permission for that directory. This is easily demonstrated as follows:

  $ cd /
  $ /usr/bin/env -i perl -e 'use Mail::Audit;'
  Error in tempfile() using mail_audit.log-XXXXX: Parent directory (.)
  is not writable at /usr/share/perl5/Mail/Audit.pm line 12

The correct usage to make tempfile() use a temporary directory would be something like:

  (undef,$logfile) =
      tempfile("mail_audit.log-XXXXX", DIR => File::Spec->tmpdir);

The second problem with having the "tempfile()" line at the top of the script when $ENV{HOME} is not present is that Mail::Audit now attempts to create a temporary log file every time it is used, even if logging is not enabled:

  $ cd /tmp
  $ /usr/bin/env -i perl -e 'use Mail::Audit;'

This creates an orphaned empty file in /tmp every time it's run.

The combination of these two problems is serious: in my case, a working script that uses Mail::Audit and doesn't do any logging (which was therefore not affected by the security bug in the first place) is now trying, and failing, to create a temporary log file in the current working directory every time the script is run, rendering the script unusable.

A proposed solution is attached. This patch only calls tempfile() if logging is actually used with a missing filename. And if logging is used, it uses "File::Spec->tmpdir" to locate "/tmp".

Although the code includes an extra "use File::Spec" for clarity, this is not actually a new dependency, because the code already uses File::Temp which depends on File::Spec anyway.

The patch also updates the documentation, which got out of sync when the behavior changed from the security update.

Thanks!

--
Robert L Mathews, Tiger Technologies    http://www.tigertech.net/

--- Audit.pm.orig	2006-02-01 10:09:05.000000000 -0800
+++ Audit.pm	2006-02-01 10:34:31.000000000 -0800
@@ -5,12 +5,6 @@
 my $logging;
 my $loglevel=3;
 my $logfile;
-if (exists $ENV{HOME} and defined $ENV{HOME} and -d $ENV{HOME}) {
-     $logfile = "$ENV{HOME}/.mail_audit.log"
-}
-else {
-     (undef,$logfile) = tempfile("mail_audit.log-XXXXX",TMPDIR=>1);
-}
 
 # ----------------------------------------------------------
 # no user-modifiable parts below this line.
@@ -25,6 +19,7 @@
 # @ISA will depend on whether the message is MIME; if it is, we'll be MIME::Entity.  if not, we'll be Mail::Internet.
 use Fcntl ':flock';
 use File::Temp qw(tempfile);
+use File::Spec;
 
 $ASSUME_MSGPREFIX = 0;
 
@@ -124,8 +119,9 @@
 You may also specify C<< log => $logfile >> to write a debugging log; you
 can set the verbosity of the log with the C<loglevel> key, on a scale of
 1 to 4. If you specify a log level without a log file, logging will be
-written to F</tmp/you-audit.log> where F<you> is replaced by your user
-name.
+written to F<.mail_audit.log> in your home directory if the HOME
+environment variable is set, or to F</tmp/mail_audit.log-XXXXX> (where
+F<XXXXX> contains random characters) if not.
 
 Usually, the delivery methods C<accept>, C<pipe>, and
 C<resend> are final; Mail::Audit will terminate when they
@@ -161,9 +157,19 @@
     open LOG, ">>/dev/null";
     if (exists $opts{loglevel}) { $logging = 1; $loglevel = $opts{loglevel}; }
     if (exists $opts{log})      { $logging = 1;                $logfile = $opts{log}; }
-    if                           ($logging)     { open LOG, ">>$logfile" or open LOG, ">>/dev/null";
-						  # this doesn't seem to propagate to the calling script.  hmm.
-					      }
+    if ($logging) {
+        unless (defined $logfile) {
+            if (exists $ENV{HOME} and defined $ENV{HOME} and -d $ENV{HOME}) {
+                $logfile = "$ENV{HOME}/.mail_audit.log"
+            }
+            else {
+                (undef,$logfile) =
+                    tempfile("mail_audit.log-XXXXX", DIR => File::Spec->tmpdir);
+            }
+        }
+        open LOG, ">>$logfile" or open LOG, ">>/dev/null";
+        # this doesn't seem to propagate to the calling script.  hmm.
+    }
 
     _log(1, "------------------------------ new run at ". localtime);
     my $draft = Mail::Internet->new( exists $opts{data}? $opts{data} : \*STDIN, Modify=>0 );

Reply via email to