--- loncom/CrGenerate.pl	2004/06/30 11:14:35	1.4
+++ loncom/CrGenerate.pl	2004/07/05 11:36:52	1.8
@@ -2,7 +2,7 @@
 # The LearningOnline Network
 # CrGenerate - Generate a loncapa certificate request.
 #
-# $Id: CrGenerate.pl,v 1.4 2004/06/30 11:14:35 foxr Exp $
+# $Id: CrGenerate.pl,v 1.8 2004/07/05 11:36:52 foxr Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -48,8 +48,8 @@
 # Import section:
 
 use strict;
+use lib '/home/httpd/lib/perl';
 use MIME::Entity;
-use Mail::Mailer;
 use LONCAPA::Configuration;
 use File::Copy;
 
@@ -71,7 +71,7 @@ my $WebGroup="www";		# Group name runnin
 
 #   Debug/log support:
 #
-my $DEBUG = 1;			# 1 for on, 0 for off.
+my $DEBUG = 0;			# 1 for on, 0 for off.
 
 # Send debugging to stderr.
 # Parameters:
@@ -80,13 +80,87 @@ my $DEBUG = 1;			# 1 for on, 0 for off.
 #    $DEBUG - message is only written if this is true.
 #
 sub Debug {
-    my $msg  = shift;
+    my ($msg)  = @_;
     if($DEBUG) {
 	print STDERR "$msg\n";
     }
 }
 
 #
+#  Decodes the email address from a textual certificate request
+#  file:
+# Parameters:
+#    $RequestFile   - Name of the file containing the textual
+#                     version of the certificate request.
+# Returns:
+#   Email address contained in the request.
+# Failure:
+#   If unable to open or unable to fine an email address in the file,
+#   dies with a message.
+#
+sub DecodeEmailFromRequest {
+    Debug("DecodeEmailFromRequest");
+
+    my ($RequestFile) = @_;
+    Debug("Request file is called $RequestFile");
+
+    # We need to look for the line that has a "/Email=" in it.
+
+    Debug("opening $RequestFile");
+    open REQUEST, "< $RequestFile" or
+	die "Unable to open $RequestFile to parse return email address";
+
+    Debug("Parsing request file");
+    my $line;
+    my $found = 0;
+    while($line = <REQUEST>) {
+	chomp($line);		# Never a bad idea.
+	if($line =~ /\/Email=/) {
+	    $found = 1;
+	    last;
+	}
+    }
+    if(!$found) {
+	die "There does not appear to be an email address in $RequestFile";
+    }
+
+    close REQUEST;
+
+    Debug("Found /Email in $line");
+    
+    # $line contains a bunch of comma separated key=value pairs.
+    # The problem is that after these is a /Email=<what-we-want>
+    # first we'll split the line up at the commas.
+    # Then we'll look for the entity with the /Email in it.
+    # That line will get split at the / and then the Email=<what-we-want>
+    # gets split at the =.  I'm sure there's some clever regular expression
+    # substitution that will get it all in a single line, but I think 
+    # this approach is gonna be much easier to understand than punctuation
+    # sneezed all over the page:
+   
+    my @commalist = split(/,/, $line);
+    my $item;
+    my $emailequals = "";
+    foreach $item  (@commalist) {
+	if($item =~ /\/Email=/) { # gotcha...
+	    $emailequals = $item;
+	    last;
+	}
+    }
+
+    Debug("Pulled out $emailequals from $line");
+    my ($trash, $addressequals) = split(/\//, $emailequals);
+    Debug("Futher pulled out $addressequals");
+
+    my ($junk, $address) = split(/=/, $addressequals);
+    Debug("Parsed final email addresss as $address");
+    
+
+
+    return $address;
+}
+
+#
 #   Read the LonCAPA web config files to get the values of the 
 #   configuration global variables we need:
 # Implicit inputs:
@@ -206,12 +280,24 @@ sub GenerateRequest {
     my $decodecmd = $SSLCommand." rsa -in  hostkey.pem"
                                ."     -out hostkey.dec"
                                ."     -passin pass:$Passphrase";
-    my $status = system($decodecmd);
+    $status = system($decodecmd);
     if($status) {
 	die "Host key decode failed";
     }
 
     chmod(0600, "hostkey.dec");	# Protect the decoded hostkey.
+
+    #  Create the textual version of the request too:
+
+    Debug("Creating textual version of the request for users.");
+    my $textcmd = $SSLCommand." req -in request.pem -text "
+	                     ." -out request.txt";
+    $status = system($textcmd);
+    if($status) {
+	die "Textualization of the certificate request failed";
+    }
+	                     
+
     Debug("Done");
 }
 #
@@ -257,8 +343,90 @@ sub InstallKey {
 
     Debug("Done");
 }
-sub MailRequest {}
-sub Cleanup {}
+#
+#  Package up a certificate request and email it to the loncapa
+#  admin.  The email sent:
+#   - Has the subject: "LonCAPA certificate request for hostname
+#   - Has, as the body, the text version of the certificate.
+#     This can be inspected by the human issuing the certificate
+#     to decide if they want to really grant it... it will
+#     have the return email and all the documentation fields.
+#   - Has a text attachment that consists of the .pem version of the
+#     request.  This is extracted by the human granting the 
+#     certificate and used as input to the CrGrant.pl script.
+#
+#
+# Implicit inputs:
+#    request.pem    - The certificate request file.
+#    request.txt    - Textual version of the request file.
+#    $RequestEmail  - Email address to which the key is sent.
+#  
+sub MailRequest {
+    Debug("Mailing request");
+
+    # First we need to pull out the return address from the textual
+    # form of the certificate request:
+
+    my $FromEmail = DecodeEmailFromRequest("request.txt");
+    if(!$FromEmail) {
+	die "From email address cannot be decoded from certificate request";
+    }
+    Debug("Certificate will be sent back to $FromEmail");
+
+    # Create the email message headers and all:
+    #
+    Debug("Creating top...level...");
+    my $top = MIME::Entity->build(Type     => "multipart/mixed",
+				  From     => $FromEmail,
+				  To       => $RequestEmail,
+				  Subject  => "LonCAPA certificate request");
+    if(!$top) {
+	die "Unable to create top level mime document";
+    }
+    Debug("Attaching Text formatted certificate request");
+    $top->attach(Path     => "request.txt");
+
+
+    Debug("Attaching PEM formatted certificate request...");
+    $top->attach(Type       => "text/plain",
+		 Path      => "request.pem");
+
+    #  Now send the email via sendmail this should work as long as
+    #  sendmail or postfix are configured properly.  Most other mailers
+    #  define the sendmail command too for compatibility with what
+    #  we're trying to do.  I decided to use sendmail directly because
+    #  otherwise I'm not sure the mail headers I created in $top
+    #  will get properly passed as headers to other mailer thingies.
+    #
+
+    Debug("Mailing..");
+
+    open MAILPIPE, "| /usr/lib/sendmail -t -oi -oem" or 
+	die "Failed to open pipe to sendmail: $!";
+    $top->print(\*MAILPIPE);
+    close MAILPIPE;
+
+
+
+    Debug("Done");
+} 
+
+#
+#   Cleans up the detritus that's been created by this 
+#   script (see Implicit inputs below).
+# Implicit inputs:
+#    request.pem       - Name of certificate request file in PEM format
+#                        which will be deleted.
+#    request.txt       - Name of textual equivalent of request file
+#                        which will also be deleted.
+#    hostkey.pem       - Encrypted host key which will be deleted.
+#    hostkey.dec       - Decoded host key, which will be deleted.
+#
+sub Cleanup {
+    Debug("Cleaning up generated, temporary files");
+    unlink("request.pem", "request.txt", "hostkey.pem", "hostkey.dec");
+    Debug("done!");
+}
 
 
 
@@ -272,3 +440,124 @@ MailRequest;			# Mail certificate reques
 Cleanup;			# Cleanup temp files created.
 
 Debug("Done");
+
+#---------------------- POD documentatio --------------------
+
+=head1 NAME
+ 
+    CrGenerate - Generate a loncapa certificate request.
+
+=head1 SYNOPSIS
+
+Usage: B<CrGenerate>
+
+This should probably be run automatically at system
+installation time.  Root must run this as write access is 
+required to /home/httpd.
+
+This is a command line script that:
+
+   - Generates a hostkey and certificate request.
+   - Installs the protected/decoded host key where
+     secure lond/lonc can find it.
+   - Emails the certificate request to the loncapa certificate
+     manager.
+
+In due course if all is legitimate, the loncapa certificate
+manager will email a certificate installation script to 
+the local loncapa system administrator.
+
+=head1 DESCRIPTION
+
+Using the default openssl configuration file, a certificate
+request and local hostkey are created in the current working
+directory.  The local host key is decoded and installed in the 
+loncapa certificate directory.  This allows the secure versions 
+of lonc and lond to locate them when attempting to form 
+external connections.  The key file is given mode
+0400 to secure it from prying eyes.
+
+The certificate request in PEM form is attached to an email that
+contains the textual equivalent of the certificate request 
+and sent to the loncapa certificate manager.  All temporary
+files (certificate request, keys etc.) are removed from the
+current working directory.
+
+It is recommended that the directory this script is run in have 
+permission mask 0700 to ensure that there are no timing holes
+during which the decoded host key file can be stolen.
+
+During certificate generation, the user will receive several 
+prompts.  For the default LonCAPA  openssl configuration, 
+these prompts, and documentation and sample responses
+in angle brackets (<>)  are shown below:
+
+    Country Name (2 letter code) [GB]: <your country e.g. US>
+    State or Province Name (full name) [Berkshire]: <State, province prefecture etc. e.g. Michigan>
+    Locality Name (eg, city) [Newbury]: <City township or  municipality e.g. East Lansing>
+    Organization Name (eg, company) [My Company Ltd]: <corporate entity e.g. Michigan State University>
+    Organizational Unit Name (eg, section) []: <unit within Organization e.g. LITE lab>
+    Common Name (eg, your name or your server's host name) [] <server's hostname e.g. myhost.university.edu>
+    Email Address []: <Address to which the granted certificate should be sent e.g. me@university.edu>
+    
+    Please enter the following 'extra' attributes
+    to be sent with your certificate request
+    A challenge password []: <leave this blank!!!!!>
+    An optional company name []: <Put whatever you want or leave blank>
+
+
+=head1  DEPENDENCIES
+
+ - MIME::Entity           Used to create the email message.
+ - LONCAPA::Configuration Used to parse the loncapa configuration files.
+ - File::Copy             Used to install the key file.
+ - /usr/lib/sendmail      Properly configured sendmail, used to send the
+                          certificate request email to the loncapa
+                          certificate administrator.
+ - /etc/httpd/conf/*      Loncapa configuration files read to locate
+                          the certificate directory etc.
+
+=head1 FILES
+
+  The following temporary files are created in the cwd
+
+  hostkey.pem         - PEM formatted version of the encrypted host key.
+  hostkey.dec         - PEM formatted decrypted version of the host key.
+  request.pem         - PEM formatted certificate request.
+  request.txt         - Textual rendering of the certificate request.
+
+  The following permanent file is created:
+
+  $CertDir/$Keyfile   - The installed decoded host key file. $CertDir
+                        is defined by the Perl variable lonCertificateDirectory
+                        in /etc/loncapa_apache.conf while $Keyfile is 
+                        defined by the perl variable lonnetPrivateKey in the
+                        same configuration file.
+  
+=head1 COPYRIGHT:
+
+ Copyright Michigan State University Board of Trustees
+
+ This file is part of the LearningOnline Network with CAPA (LON-CAPA).
+
+ LON-CAPA is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or 
+ (at your option) any later version.
+
+ LON-CAPA is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with LON-CAPA; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+ /home/httpd/html/adm/gpl.txt
+
+
+=cut
+
+
+