Sunday, August 4, 2013

IIS and FormMail.pl and Perl Taint Mode and Email Relay

Apparently Perl taint mode and NMS FormMail do not always play together well when running on a Microsoft IIS web server. Why? I don't pretend to understand why.

I only know that when I changed this:

#!/usr/bin/perl -wT

to this:

#!/usr/bin/perl -w

my script started to run. That is to say, when I turned taint mode off under IIS, my FormMail.pl script, which would not run at all, started to run.

I'm not claiming that this is a cure-all for FormMail.pl problems under IIS. Here's what the top of my FormMail.pl script currently looks like:

#!/usr/bin/perl -w
#
# NMS FormMail Version 3.14c1
#

use strict;
use vars qw(
  $DEBUGGING $emulate_matts_code $secure %more_config
  $allow_empty_ref $max_recipients $mailprog @referers
  @allow_mail_to @recipients %recipient_alias
  @valid_ENV $date_fmt $style $send_confirmation_mail
  $confirmation_text $locale $charset $no_content
  $double_spacing $wrap_text $wrap_style $postmaster 
  $address_style
);

print "Content-type: text/html\n\n";
print "<html>\n";
print "<head>\n";
print "<title>Got here 1</title>\n";
print "</head>\n";
print "<body>\n";
print "<h1>Got here 1</h1>\n";
print "<p>Got here 1</p>\n";
print "</body>\n";
print "</html>\n";

__END__

Nothing brilliant here. I've basically done three things with the above code:

  1. Turn off taint mode by taking the T off of -wT in the shebang syntax on the first line of code
  2. Add a little bit of Got here code that is sent to my browser
  3. Exit with a perl __END__ statement

As of now, I've only tried running the top few lines (shown above) with taint mode off. For all I know, the whole program could now work. I'll try running the whole program next.

Update: August 4, 2013, 7:47 PM

I've tried running the whole program. More problems. Seems that I'm getting this error code coming back from the mail server:

554 5.5.2 No valid recipients

Here's a Perl module that can be used to test a mail relay to make sure it is working:

Net::SMTP

Note the following example code from the above link:

  #!/usr/local/bin/perl -w

    use Net::SMTP;

    $smtp = Net::SMTP->new('mailhost');

    $smtp->mail($ENV{USER});
    $smtp->to('postmaster');

    $smtp->data();
    $smtp->datasend("To: postmaster\n");
    $smtp->datasend("\n");
    $smtp->datasend("A simple test message\n");
    $smtp->dataend();

    $smtp->quit;

For me, the above code is a great start. However, I need code that will work on a remote webserver that will send the output to my web browser. The following modifies the above code so that it will work in your browser:

Mail Relay Testing With a Perl Script

In the final example on the above page, the original poster (OP) called ccc solves his own problem. In the first few lines of his solution, he sets up his email headers:

#!/usr/bin/perl -w

use Net::SMTP;

$from = 'me@mydomain.net';
$to = 'me@mydomain.net';
$subject = 'relay test';
$server = 'IP_address_of_the_mail_server';

In his code, he mentions IP_address_of_the_mail_server.. In many cases, this will be 127.0.0.1. Many web hosts use 127.0.0.1 as the address of their mail relay to keep things simple for their customers.

Of course, 127.0.0.1 is local host. When you use this address on your webserver, the webserver is referring to itself. In other words, 127.0.0.1 is self-reference. Perhaps this is an example of your mail server and your web server being on the same physical box, the same physical computer.

For $from and $to you might choose to use any email address that you think will work or would like to get working. In my case, I'm using my Gmail email address.

Unfortunately, my Gmail address is not working. Since I'm getting a very general server error, I suspect it is because the web hosting company I'm working with is refusing to relay email to my Gmail.

I suspect the reason that I cannot relay email to Gmail is because the hosting company does not allow it. Internally, they have an approved list of email addresses that you can relay to and my email address is not on that list.

Refusing to relay email to non-approved email addresses is quite common. It's a preventive measure, really. It's to prevent an email relay from becoming an open spam relay.

So, the only thing for me to do now is to call the hosting company I'm working with and ask them to relay email to my Gmail address. Unfortunately, since they don't give me a control panel to work with, I have to talk to a live person (or email them).

Back to the solution provided by CCC.

After the email headers are set up, an HTTP header is sent:

print "Content-type: text/plain\n\n";

As simple as this one line of code is, it enables your browser to handle what comes next. Basically, the above HTTP header concerning the content type says display what follows in my browser window. That is to say, that's the overall effect.

The next line of code sends all errors generated by your Perl script to your browser:

open STDERR, ">&STDOUT";

The above line of code says STDERR and STDOUT are going to the same place. Since STDOUT is already going to your browser, STDERR is now going to the same place --- your browser.

Perhaps a better way to interpret the above line of code is send STDERR to STDOUT. That's the literal meaning.

The next line of code is called a constructor. It constructs an object that you use to communicate with your mail server. In this case, the object is called $smtp.

$smtp = Net::SMTP->new($server, Debug => 1);

The above line of code does more than just construct an object called $smtp. It also turns on debugging.

Remember STDERR? This where STDERR comes in. In these two lines two things are happening:

  1. Debugging has been turned on
  2. All debugging is being sent to your browser

When I say all debugging is being sent to your browser, I mean all error messages are being sent to your browser.

Of course, in the above code, these two steps happen in reverse order. Here's the code again:

open STDERR, ">&STDOUT";

$smtp = Net::SMTP->new($server, Debug => 1);

After this, the code manipulates the object called $smtp to good effect:

$smtp->mail($from);
$smtp->to($to);

$smtp->data();
$smtp->datasend("To: $to\n");
$smtp->datasend("Subject: $subject\n");
$smtp->datasend("\n");
$smtp->datasend("A simple relay test message\n");
$smtp->dataend();

$smtp->quit;

The last line of code is probably unnecessary:

close STDERR;

It appears to me that the last line of code is there for good form only. Since perl closes all files at the end of the script, STDERR would be closed anyway.

However, following good form and good coding practices is important. There's really no reason why you should not explicitly close a file. By unnecessary, I only mean to say that the last line of code really doesn't change anything --- it would happen anyway.

Update: August 17, 2013

In re-reading my post, I see I got a bit off-track. I started off by turning off perl taint mode to see if I could get formmail running on an IIS server. I did get it to run but did not get it to work.

It did not work because the email relay at the hosting company was not working. So, I went looking for a program that would test the email relay.

I found a program that tested the email relay but, unfortunately, it would not work as-is in my browser. So, I found another web page that told me how to modify the program to work in my browser since I have no access to the webserver I'm working on except browser access and FTP access.

By the way. The email relay is now working. The web hosting company came through by giving me permission to relay the specific email addresses I asked them to relay.

This is probably an example of a web hosting company relaying only known email addresses so as to avoid becoming an open spam relay. Web hosting companies have to be super-careful these days about inadvertantly relaying spam.

Update: August 19, 2013

Since this post has transformed into a discourse on Net::SMTP, I've decided to continue my thoughts here:

Email Relay Testing With Perl

Update: August 22, 2013

According to this post, Windows does not need the shebang line at all:

What Should I Use for a Perl Script's Shebang line?

It appears to me that Windows uses the .pl extenstion instead to execute your Perl Script. However, if you have a shebang line with Taint mode specified, in addition to having a .pl extenstion, it seems to be a problem. Why? I don't know why.

Since ActiveState Perl (read, Windows Perl) does not use the shebang line, maybe I would be better off without the shebang. I should probably just remove the shebang line.

The rather bizarre impression I'm getting is that ActiveState Perl does not use the shebang line, but IIS web server tries to use it anyway. Is this possible? I'm not sure. I don't know enough about the interaction between IIS web server and ActiveState Perl to know why this would be true or would not be true. Just a theory right now.

Ed Abbott

No comments:

Post a Comment