8.3.11 Sending Email from a CGI Program
8.3.11 Sending Email from a CGI Program
In this section, we discuss a CGI program which is very much like the others we have discussed earlier, except that the CGI program sends electronic mail from within the code after a form has been filled. A user is presented a form. After the user fills the form and submits it, the form data is sent to the server where a CGI program takes control of the processing. First, the CGI program obtains the values of the form fields. The form contains details necessary for membership of a cultural organization called ASA. A portion of the form is shown in Figure 8.15. Next, the program creates an electronic mail message regarding the details of the new member and sends the message to those who keep
records. Once the e-mail has been sent, the program creates an HTML page that it sends back to the browser.
Program 8.13
#!/usr/bin/perl -Tw
#file asa_membership_form.pl
use CGI qw(:standard);
use CGI::Carp qw(fatalsToBrowser);
use Untaint;
use strict;
##########
$CGI::POST_MAX = 1024; #max 1024 bytes posts
$CGI::DISABLE_UPLOADS = 1;
#print header information
print "Content-type: text/html\n\n";
my $year = param ("year");
my $membership_type = param ("membership_type");
my $general_donation = param ("general_donation");
my $endowment_donation = param ("endowment_donation");
my $donation_target = param ("donation_target");
my $other_donation = param ("other_donation");
my $name = param ("name");
my $spouse_name = param ("spouse_name");
my $children_name = param ("children_name");
my $address = param ("address");
my $phone_no = param ("phone_no");
my $mail_address = param ("mail_address");
my $WWW_Home_Page = param ("WWW_Home_Page");
($membership_type, $donation_target, $name, $spouse_name, $children_name)
= untaint (qr{^[\w\s]+},
$membership_type, $donation_target, $name, $spouse_name,
$children_name);
($year, $general_donation, $endowment_donation, $other_donation)
= untaint (qr{^\d+(.\d\d)?$},
$year, $general_donation, $endowment_donation, $other_donation);
$address = untaint (qr{^[\d\w\s]+$}, $address);
$mail_address = untaint (qr{^[\w.]+@[\w.]+$}, $mail_address);
$phone_no = untaint (qr/^\d{3} ?\d{3} ?\d{4}$/, $phone_no);
$WWW_Home_Page = untaint (qr{^[\w\d.-/]+$}, $WWW_Home_Page);
my $asaexecs = "asaexecs\@pikespeak.uccs.edu";
$ENV{PATH} = "";
open (MAIL, "|/bin/mail $asaexecs");
print MAIL "ASA Membership Form\n";
print MAIL qq{
year: $year
membership_type: $membership_type
general_donation: $general_donation
endowment_donation: $endowment_donation
donation_target: $donation_target
other_donation: $other_donation
name: $name
spouse_name: $spouse_name
children_name: $children_name
address: $address
phone_no: $phone_no
mail_address: $mail_address
WWW_Home_Page: $WWW_Home_Page
};
close (MAIL);
my $date = `date`;
print qq{
ASA Membership For The Year $year!
ASA Membership!
Dear $name,
Thank you for becoming a member of ASA. We
appreciate your interest in the activities of the ASA.
Please make plans to attend our next annual convention.
Please do not forget to send in your contribution check soon.
Sincerely,
K. Bhuyan,
President, Mays Landing, New Jersey, USA
$date
};
The program first creates an HTTP header to send out with the HTML response page to the browser. Next, it captures the values of all the form fields. After this, the program creates a mail message to be sent to the global mail alias asaexecs@pikepeak.uccs.edu. The mail message is created using a Unix pipe, first discussed in Section 7.2.3. A pipe can be used in Unix to communicate among processes. For example, the input of one command can be sent to another for further processing. Here, our Perl program is a process and the system mail program /bin/mail is another process. It
should be noted that the system mail program may be at different locations on different machines such as /bin/mail or /usr/ucb/mail. On Mac OS X server, it is at /usr/bin/mail. Therefore, for this program to work, we should be on a Unix machine and know where the mail program is located. The communication between the current program and the mail program is established by the open command.
open (MAIL, "|/bin/mail $asaexecs");
After this statement is executed, an outgoing line of communication is established between the Perl script and the mail program. The | in front says that the current process, i.e., the current Perl script, pipes data out to the /bin/mail process. The pipe that communicates between the two programs is called MAIL. The MAIL pipe accumulates information from the current program and delivers them to the mail program only after the current program closes the pipe. Thus, when the program executes the following statement,
print MAIL "ASA Membership Form\n";
the string ASA Membership Form is printed to the pipe, but not sent to mail program yet. So, it is buffered. Till it has to be sent out. Similarly, any other writing to the pipe is buffered. All the values captured from the HTML form are written to the mail message using a simple format. Finally, the pipe is closed.
close (MAIL);
At this point the information in the buffer is piped into the mail program and the mail message sent. The mail message sent looks like the following.
Return-Path: apache@pikespeak.uccs.edu
Delivery-Date: Tue Jun 26 10:08:18 2001
Delivery-Date: Tue, 26 Jun 2001 10:08:18 -0600
Received: (from apache@localhost)
by pikespeak.uccs.edu (8.11.0/8.11.0) id f5QG8I301548
for asaexecs@pikespeak.uccs.edu; Tue, 26 Jun 2001 10:08:18 -0600
Date: Tue, 26 Jun 2001 10:08:18 -0600
From: Apache <apache@pikespeak.uccs.edu>
Message-Id: <200106261608.f5QG8I301548@pikespeak.uccs.edu>
To: asaexecs@pikespeak.uccs.edu
ASA Membership Form
year: 01
membership_type:
general_donation: 100
endowment_donation: 100
donation_target:
other_donation: 100
name: Jugal Kalita
spouse_name:
children_name:
address: 1420 Austin Bluffs Parkway
Colorado Springs CO 80917
phone_no: 719 262 3432
mail_address:
WWW_Home_Page: http://www.cs.uccs.edu/~kalita
The program creates the HTML page it sends to the browser The Web page displayed on the browser looks like that in Figure 8.16.
Figure 8.15: Filling up a Membership Form for an Organization
Figure 8.16: Filling up a Membership Form for an Organization
The CGI program given in this Section is security-conscious. It limits the size of the CGI parameter data to 1024 bytes. It disables file uploads. It untaints all inputs from the associated HTML form. untaint, as used here, uses a compiled regular expression to launder a list of values. The purpose of data laundering by a Perl program is to make sure that it will not allow data from outside a program be propagated through it to influence something else outside the program, at least by accident. This is simply being a good citizen. In the taint mode, Perl is paranoid and will die
even at a hint of such influence i.e., unless the outside data has been validated. Perl is a large binary, hard to test and audit, so the language designers assume that it contains security holes. The taint system is another layer of protection.
A final point to note about the security strategies used by the program is that it sets the value of $ENV{PATH} environment variable to the empty string before it uses a Perl pipe to send email using /bin/mail.
$ENV{PATH} = "";
open (MAIL, "|/bin/mail $asaexecs");
This is important because we do not want the CGI program, that can be run in response to anyone in the world clicking on a submit button in an HTML form to have access to the original PATH information on the server. The PATH information is used by system calls inside the program, including pipe calls, to find the location of system commands that do not use absolute address. In the above, we have used /bin/mail as the command and it is in absolute format, and therefore,
the PATH information does not matter. However, the taint mode of Perl, requires a CGI program to set the value of $ENV{PATH} inside the program so that only safe and well-known directories can be searched to find commands for which relative locations are given. In our case, setting it to the empty string suffices. Thus, one must know the absolute address of a program so that it can be run from within Perl. Setting of PATH inside program is mandatory in taint mode because Perl cannot guarantee that the executable in question (here,
/bin/mail isn’t itself going to turn around and execute some other program that is dependent on the PATH. Therefore, it makes sure the programmer consciously set the PATH. Although we set the value to the empty string, a more usual assignment is the following.
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin';
One can add other safe and well-known directories if needed. One should *not* add "." or one’s own directory to the list in this statement. This assignment only allows programs from the directories /bin, /usr/bin/, and /usr/local/bin to run. These are system directories, and presumably are safe.
One might ask “What is unsafe about the path? ". Historically, paths have been considered unsafe because if there are multiple versions of an executable, it is difficult to tell which one is actually being executed. If there is a bug in one of the versions, then this can pose a security hazard.
