> RYAN, PAT OCT TUT LISTING FILE > LC: 212 1. An HTML form, **order.html**, used by the fictitious Yoyodyne Corp. to collect order information via Mosaic. Yoyodyne Corp. Product Order Form

Product Order


Items to order:

Choose method of payment:

If using a corporate account, please enter your account number and authorization key:

Click here to send a carbon-copy of your order to your email address (as specified above).


2. The CGI program, **process_order**, called from within **order.html**. #!/usr/bin/perl # eval "exec /usr/bin/perl -S $0 $*" if $running_under_some_shell; # extra include directories push(@INC,'/app/people/guide/GUIDE/server/WWW/httpd_1.1/cgi-bin'); require 'ctime.pl'; require 'cgi-lib.pl'; chop($now = &ctime(time())); # Read in everything from httpd. &ReadParse; # Send the initial info back to the server. print &PrintHeader; print "Results of Your Order Submission\n"; unless ($in{'name'}) { print "You must include your name in any order.

"; exit 0; } if ($in{'cc'} && !$in{'email'}) { print <<_EOT_; You asked for a carbon copy of your order but did not include your email address. Please add your address and resubmit your order.

_EOT_ exit 0; } # Open up temporary file for ordering system $order_file = "/tmp/order.$$"; open(ORDER,">$order_file"); print ORDER <<_EOT_; NAME: $in{'name'} ADDRESS: $in{'address'} PHONE: $in{'phone'} EMAIL: $in{'email'} PAYMENT: $in{'payment'} ACCOUNT: $in{'account'} AUTHORIZATION: $in{'key'} _EOT_ print ORDER "ITEMS:\n"; $n=0; foreach(split(/\n/,$in{'items'})) { ++$n; printf ORDER "%3d\t%s\n",$n,$_; } print ORDER "RECEIVED: $now\n"; print ORDER "\n"; print ORDER <<_EOT_; REMOTE: $ENV{'REMOTE_HOST'} _EOT_ print ORDER "\n"; close ORDER; # Send the order to the Processing database $cmd = "/usr/local/bin/process_order $order_file"; system $cmd; # If requested, send the user a copy of the order. if ($in{'cc'} && $in{'email'}) { @addresses=($in{'email'}); $to = join(' ',@addresses); # Escape any suspicious characters $to=&protect($to); $mail_cmd = "/bin/mail"; $cmd = "$mail_cmd $to"; unless (open(MAIL,"| $cmd")) { print <<_EOT_; An error occurred while trying to submit your order. Please contact root@yoyodyne.com.

_EOT_ exit 0; } print MAIL "\n"; open(ORDER,"<$order_file"); while () { print MAIL $_; } print MAIL "\n"; close MAIL; close ORDER; } print <<_EOT_; Thank you. Your order was received at $now and has been sent to the Processing Department.

_EOT_ unlink($order_file); exit 0; sub protect # Quotify characters which are special to the shell { local($_)=@_; s!([;:&\$'`|()])!\\$1!g; # Use backslash to escape metacharactors $_; } 3. Test script **cgi_test** #!/usr/bin/perl # # CGI script to process Software Modification Requests (SMRs) # ryan@odouls.stx.com (patrick m. ryan) # eval "exec /usr/bin/perl -S $0 $*" if $running_under_some_shell; # extra include directories push(@INC,'/app/people/guide/GUIDE/server/WWW/httpd_1.1/cgi-bin'); push(@INC,'/app/people/ryan/perl'); require 'cgi-lib.pl'; require 'date.pl'; $now = &date(time()-(4*3600)); select STDOUT; $|=1; # Suck in everything from httpd. &ReadParse; print &PrintHeader; print "CGI test\n"; print &PrintVariables(%in); print &PrintVariables(%ENV); exit 0; Table 1: Routines available in the **cgi-lib.pl** Perl library, and useful in writing CGI scripts. [*] ReadParse Read and parse the input from the server. After this routine has been run, several global variables will exist: **$in** a scalar that contains the entire input line. **@in** an array of strings of the form __name=value__. **%in** an associative array where **$in{**__name__**}=**__value__. [*] PrintHeader Returns a line meant to be the first line sent back to standard output. [*] PrintVariables Collects all of the form values and formats them into an HTML unordered list suitable for sending to standard output. This routine is useful for testing. [Listing 4. This didn't appear in the printed version--had to be cut for space reasons. rf] You have an HTML form that returns a variable called **address** that should contain a user's email address. In your Perl CGI script, you have copied this value to a variable called **$address**. You want to mail some information to this address so you put the following code in your Perl CGI program: # Send confirmation back to the user. open(MAIL, "|/bin/mail $address"); print MAIL "Your order has been sent to the Processing Department. Your PO number is $number\n"; close MAIL; A normal user would send a value like **joe@verylarge.com**. The second parameter to Perl's **open()** function would be sent a value of "|/bin/mail joe@verylarge.com". No problem. The unscrupulous cracker, however, might use a bogus address and then follow it with a semicolon and another command. This cracker could type "/dev/null; rm -rf /home". Unless the CGI program notices the semicolon embedded in the **$address** address, the **open()** command would be sent "|/bin/mail /dev/null; rm -rf /home". **/bin/mail** would cheerfully send a message to **/dev/null**. The system would then treat the text after the semicolon as another command and merrily proceed to destroy the **/home** filesystem. [end listing 4] -30-