--- loncom/CrGrant.pl 2004/07/02 10:51:18 1.1 +++ loncom/CrGrant.pl 2004/07/05 11:37:39 1.2 @@ -2,7 +2,7 @@ # The LearningOnline Network # CrGrant.pl - Grant a loncapa SSL certificate. # -# $Id: CrGrant.pl,v 1.1 2004/07/02 10:51:18 foxr Exp $ +# $Id: CrGrant.pl,v 1.2 2004/07/05 11:37:39 foxr Exp $ # # Copyright Michigan State University Board of Trustees # @@ -55,14 +55,8 @@ # o The certificate authority files are in $SSLDir/loncapaca # o The certificate authority certificate is in: # $SSLDir/loncapaca/cacert.pem -# o The certificate authority maintains a certificate index file -# $SSLDIR/loncapaca/index.txt -# o Only one instance of this script will be run at a time!!!!! -# (otherwise the last line of the index file may not be the -# index to our certificate. We'll do some rudimentary -# error checking, but have no idea how to recover in case -# of problems). -# o The generated certificates are stored in $SSLDIR/loncapaca/certs +# o Only one instance of this script will be run at a time in +# this directory. # o The person that runs this script knows the passphrase # for the loncapa certificate authority's private key # which remains encrypted for security reasons. @@ -80,7 +74,12 @@ use LONCAPA::Configuration; # Global variable declarations +my $ssl_command = "/usr/bin/openssl "; # Command to run openssl. +my $ssl_dir = "/usr/share/ssl"; # Where ssl config files etc. live +my $ca_cert_file = $ssl_dir."/loncapa/cacert.pem"; # CA's certificate file. +my $ca_config_file= $ssl_dir."/loncapaca.cnf"; # CA's config file. + # Debug/log support @@ -94,12 +93,126 @@ sub Debug { } # Support subs: -sub Usage {} +# +# Print out program usage. +# +# Side effects: +# Output goes to stderr. +# +sub Usage { + print STDERR << "USAGE"; + +Usage: + CrGrant.pl requestfile.pem +Where: + requestfile.pem is a PEM formatted certificate extracted from an email + to the LonCAPA certificate manager. +USAGE + +} +# Create a certificate from the request file. The certificate +# is used, in conjunction with the openssl command with the +# certificate authority configuration to produce a certificate +# file. +# +# The certificate is parsed to determine the email address +# of the requestor, which is returned to the caller. +# +#Parameters: +# request_file - Name of the file containing the certificate request. +#Returns: +# If the request file exists and is able to produce a certificate +# the email address of the requester is returned to the caller. +# If not, undef is returned. +# sub CreateCertificate { - my $RequestFile = shift; + my ($request_file) = @_; + + Debug("CreateCertificate"); + + if(!(-e $request_file)) { + Debug("Certificate file $request_file does not exist"); + return undef; + } + Debug("Certificate file $request_file exists"); + + # Create the certificate: The status of the openssl command + # is used to determine if the certificate succeeded: + + my $create_command = $ssl_command." ca -config ".$ca_config_file + ." -in ".$request_file + ." -out hostCertificate.pem"; + my $status = system($create_command); + if($status) { + Debug("openssl ca failed"); + print STDERR "Certificate generation failed... probably bad"; + print STDERR " request file!\n"; + return undef; + } + Debug("openssl ca succeeded"); + + # Now we have a shining new signed certificate in ./hostCertificate.pem + # we parse it to get the email address to which the certificate should + # be emailed. + # The certificate's return email address will be in the Subject line: + # + + Debug("Parsing certificate file for Subject:"); + open CERTIFICATE, ") { + Debug("Line = $line"); + if($line =~ /Subject:/) { + Debug("Found Subject: in $line"); + $subject_found =1; + last; + } + } + close CERTIFICATE; + + if(!$subject_found) { + Debug("Did not find Subject line in cert"); + print STDERR "Output certificate parse failed: no Subject:\n"; + return undef; + } + # The subject line contains an Email= string amidst the other stuff. + # First break in to comma separated stuff, then locate the piece that + # contains /Email= + + my @subject_fields = split(/,/, $line); + my $email_found = 0; + my $element; + my $email_element; + Debug("Parsing subject line for Email="); + foreach $element (@subject_fields) { + $email_element = $element; + Debug("Parsing $element"); + if($element =~ /\/Email=/) { + Debug("Found /Email="); + $email_found = 1; + last; + } + } + if(!$email_found) { + Debug("Failed to fine Email="); + print STDERR "Unable to find line with /Email= in cert. Subject\n"; + return undef; + } + + # The piece we found must first be split at the / + # to isolate the Email= part and then that part at the = to isolate + # the address: + + Debug("Splitting $email_element at /"); + my ($junk, $email) = split(/\//, $email_element); + Debug("Email part is $email"); + my ($junk, $address) = split(/=/, $email); + Debug("CreateCertificate Returning $address to caller"); + + return $address; - return 'fox@nscl.msu.edu'; # Stub.. } sub CreateInstallScript {} @@ -125,10 +238,17 @@ if($argc != 1) { } my $CertificateRequest = $ARGV[0]; -my $EmailAddress = CreateCertificate($CertificateRequest); +my $email_address = CreateCertificate($CertificateRequest); + +if(!defined $email_address) { + print STDERR "Bad or missing certificate file!!"; + Usage; + exit -1; +} + CreateInstallScript; my $Message = CreateEmail; -SendEmail($EmailAddress, $Message); +SendEmail($email_address, $Message); Cleanup; # POD documentation.