Bug#387003: SetSender ignored if send() called with no parameters

Shane Allen sallen at hrsmart.com
Mon Sep 11 15:58:57 UTC 2006


Package: libmime-lite-perl
Version: 3.01-4

This is basically a duplicate of CPAN #2759 [1]. I will be updating the CPAN report as well.

>From the documentation:

-- begin --

SetSender

Unless this is explicitly given as false, we attempt to automatically set the -f argument to the first address that can be extracted from
the "From:" field of the message (if there is one).

What is the -f, and why do we use it?
Suppose we did not use -f, and you gave an explicit "From:" field in your message: in this case, the sendmail "envelope" would indicate the real user your process was running under, as a way of preventing mail forgery.  Using the -f switch causes the sender to be set in the envelope as well.

-- end --

A simple test case:

root at test:~# cat test.pl
#!/usr/bin/perl -w

use strict;
use MIME::Lite;

my $msg = MIME::Lite->new(
             From     =>'foo at hrsmart.com',
             To       =>'sallen at hrsmart.com',
             Subject  =>'Helloooooo, nurse!',
             Data     =>"How's it goin', eh?"
             );
$msg->send();

root at test:~# perl test.pl
root at test:~# tail -3 /var/log/exim/mainlog
2006-09-11 10:30:04 1GMnjX-0007Br-00 <= root at hrsmart.com U=root P=local S=507
2006-09-11 10:30:04 1GMnjX-0007Br-00 => sallen at hrsmart.com R=lookuphost T=remote_smtp H=mail.hrsmart.com [xx.xx.xx.xx]
2006-09-11 10:30:04 1GMnjX-0007Br-00 Completed

Here's the resulting message source:

X-Real-To: sallen at hrsmart.com
Return-Path: <root at hrsmart.com>
Received: from test.hrsmart.com ([xx.xx.xx.xx] verified)
  by franklin.hrsmart.com (SMTP)
  with ESMTP id 2191773 for sallen at hrsmart.com; Mon, 11 Sep 2006 10:30:20 -0500
Received: from root by test.hrsmart.com with local (Exim 3.36 #1 (Debian))
	id 1GMnjX-0007Br-00
	for <sallen at hrsmart.com>; Mon, 11 Sep 2006 10:30:03 -0500
Content-Disposition: inline
Content-Length: 19
Content-Transfer-Encoding: binary
Content-Type: text/plain
MIME-Version: 1.0
X-Mailer: MIME::Lite 3.01 (F2.72; B3.04; Q3.03)
Date: Mon, 11 Sep 2006 15:30:02 UT
From: foo at hrsmart.com
To: sallen at hrsmart.com
Subject: Helloooooo, nurse!
Message-Id: <E1GMnjX-0007Br-00 at test.hrsmart.com>

How's it goin', eh?

An alternate test case:

root at test:~# cat test.pl
#!/usr/bin/perl -w

use strict;
use MIME::Lite;

my $msg = MIME::Lite->new(
             From     =>'foo at hrsmart.com',
             To       =>'sallen at hrsmart.com',
             Subject  =>'Helloooooo, nurse!',
             Data     =>"How's it goin', eh?"
             );
$msg->send_by_sendmail();

root at test:~# perl test.pl
root at test:~# tail -3 /var/log/exim/mainlog
2006-09-11 10:36:50 1GMnq6-0007Cg-00 <= foo at hrsmart.com U=root P=local S=507
2006-09-11 10:36:50 1GMnq6-0007Cg-00 => sallen at hrsmart.com R=lookuphost T=remote_smtp H=mail.hrsmart.com [xx.xx.xx.xx]
2006-09-11 10:36:50 1GMnq6-0007Cg-00 Completed

Message source:

X-Real-To: sallen at hrsmart.com
Return-Path: <foo at hrsmart.com>
Received: from test.hrsmart.com ([xx.xx.xx.xx] verified)
  by franklin.hrsmart.com (SMTP)
  with ESMTP id 2191967 for sallen at hrsmart.com; Mon, 11 Sep 2006 10:37:06 -0500
Received: from root by test.hrsmart.com with local (Exim 3.36 #1 (Debian))
	id 1GMnq6-0007Cg-00
	for <sallen at hrsmart.com>; Mon, 11 Sep 2006 10:36:50 -0500
Content-Disposition: inline
Content-Length: 19
Content-Transfer-Encoding: binary
Content-Type: text/plain
MIME-Version: 1.0
X-Mailer: MIME::Lite 3.01 (F2.72; B3.04; Q3.03)
Date: Mon, 11 Sep 2006 15:36:50 UT
From: foo at hrsmart.com
To: sallen at hrsmart.com
Subject: Helloooooo, nurse!
Message-Id: <E1GMnq6-0007Cg-00 at test.hrsmart.com>

How's it goin', eh?

Things to note:

1. The log lines in test #2 shows the message from foo, not root.
2. The Return-Path header in #2 shows the message from foo, not root.

These are the effects of the SetSender flag. It is supposed to be active by default, per the documentation.

The problem is a result of an inconsistency in send_by_sendmail, which I am filing an additional bug report about. send_by_sendmail has two "modes" of operation. In the first, if arguments are passed in, no further processing is done. A pipe is opened to sendmail, and the message is sent using that pipe. The sendmail instance is executed using only the arguments passed in to send_by_sendmail; no further processing is done. This means the SetSender flag is ignored.

The *actual* problem causing this issue is because the send() function uses default arguments for send_by_sendmail, which triggers the inconsistent behaviour noted above. From the module source:

    380 ### Our sending facilities:
    381 my $Sender     = "sendmail";
    382 my %SenderArgs = (
    383     "sendmail" => ["$SENDMAIL -t -oi -oem"],
    384     "smtp"     => [],
    385     "sub"      => [],
    386 );

.... <snip> ....

   2440 sub send {
   2441     my $self = shift;
   2442
   2443     if (ref($self)) {              ### instance method:
   2444         my ($method, @args);
   2445         if (@_) {                            ### args; use them just this once
   2446             $method = 'send_by_' . shift;
   2447             @args   = @_;
   2448         }
   2449         else {                               ### no args; use defaults
   2450             $method = "send_by_$Sender";
   2451             @args   = @{$SenderArgs{$Sender} || []};
   2452         }
   2453         $self->verify_data if $AUTO_VERIFY;  ### prevents missing parts!
   2454         return $self->$method(@args);
   2455     }

.... <snip> ....

   2536 sub send_by_sendmail {
   2537     my $self = shift;
   2538
   2539     if (@_ == 1) {                    ### Use the given command...
   2540         my $sendmailcmd = shift @_;
   2541
   2542         ### Do it:
   2543         open SENDMAIL, "|$sendmailcmd" or Carp::croak "open |$sendmailcmd: $!\n";
   2544         $self->print(\*SENDMAIL);
   2545         close SENDMAIL;
   2546         return (($? >> 8) ? undef : 1);
   2547     }
   2548     else {                            ### Build the command...
   2549         my %p = @_;
   2550         $p{Sendmail} ||= "/usr/lib/sendmail";
   2551
   2552         ### Start with the command and basic args:
   2553         my @cmd = ($p{Sendmail}, @{$p{BaseArgs} || ['-t', '-oi', '-oem']});
   2554
   2555         ### See if we are forcibly setting the sender:
   2556         $p{SetSender} = 1 if defined($p{FromSender});
   2557
   2558         ### Add the -f argument, unless we're explicitly told NOT to:
   2559         unless (exists($p{SetSender}) and !$p{SetSender}) {
   2560             my $from = $p{FromSender} || ($self->get('From'))[0];


Suggested fixes:

1. Move the default argument construction to a separate function:

sub build_sendmail_args
{
    # do the work occurring in lines 2549 - 2965
}

2. Change Sender Args like so:

    380 ### Our sending facilities:
    381 my $Sender     = "sendmail";
    382 my %SenderArgs = (
    383     "sendmail" => [ build_sendmail_args() ],
    384     "smtp"     => [],
    385     "sub"      => [],
    386 );

3. Modify sub send_by_sendmail to use build_sendmail_args (to avoid code duplication)

4. Modify the documentation:

SetSender

Unless this is explicitly given as false **or unless you override the arguments being passed to sendmail**, we attempt to automatically set the -f argument to the first address that can be extracted from the "From:" field of the message (if there is one).


[1] <http://rt.cpan.org/Public/Bug/Display.html?id=2759>




More information about the pkg-perl-maintainers mailing list