Diff for /loncom/CrGrant.pl between versions 1.1 and 1.3

version 1.1, 2004/07/02 10:51:18 version 1.3, 2004/07/06 11:05:45
Line 55 Line 55
 #      o The certificate authority files are in $SSLDir/loncapaca  #      o The certificate authority files are in $SSLDir/loncapaca
 #      o The certificate authority certificate is in:  #      o The certificate authority certificate is in:
 #         $SSLDir/loncapaca/cacert.pem  #         $SSLDir/loncapaca/cacert.pem
 #      o The certificate authority maintains a certificate index file  #      o Only one instance of this script will be run at a time in
 #        $SSLDIR/loncapaca/index.txt  #        this directory.
 #      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 The person that runs this script knows the passphrase  #      o The person that runs this script knows the passphrase
 #        for the loncapa certificate authority's private key  #        for the loncapa certificate authority's private key
 #        which remains encrypted for security reasons.  #        which remains encrypted for security reasons.
Line 72 Line 66
 # Import section:  # Import section:
   
 use strict;  use strict;
 use lib '/home/httpd/lib/perl';  use lib '/home/httpd/lib/perl'; # An assumption!!!
 use MIME::Entity;  use MIME::Entity;
 use LONCAPA::Configuration;  use LONCAPA::Configuration;
   
Line 81  use LONCAPA::Configuration; Line 75  use LONCAPA::Configuration;
 # Global variable declarations  # Global variable declarations
   
   
   my $ssl_dir       = "/usr/share/ssl";    # Where ssl config files etc. live
   my $ca_cert_file  = $ssl_dir."/loncapaca/cacert.pem"; # CA's certificate file.
   my $ca_config_file= $ssl_dir."/loncapaca.cnf";      # CA's config file. 
   
   
   #   LONCAPA Configuration global variables:
   
   # Items read from our configuration file.
   
   my $ssl_command   = "/usr/bin/openssl "; # Command to run openssl.
   my $loncapa_cert_dir; # Name of target cert dir (from config)
   my $loncapa_hostcert_name; # Name of host's signed cert file (config)
   my $loncapa_cacert_name;        # Name of the CA's certificate file (config)
   
   #  Items I just need to know:
   
   my $loncapa_config = "loncapa.conf";   # User's override config file.
   my $loncapa_apache_user = 'www'; # Name of apache daemon's user
   my $loncapa_apache_group = 'www'; # Name of apache daemon's group
   
   
   
 # Debug/log support  # Debug/log support
   
Line 94  sub Debug { Line 109  sub Debug {
 }  }
 #  Support subs:  #  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
   
   }
   #
   #  Read the loncapa configuration file and pull out the items
   #  we need:
   #
   # Implicit inputs:
   #   $loncapa_config   - The name of the auxilliary config file.
   # Side effects:
   #    - On failure exits with an error message.
   #    - On success set the following variables:
   #      o loncapa_cert_dir      - Path to certificates.
   #      o loncapa_hostcert_name - Name of host's cert file in that dir
   #      o loncapa_cacert_name   - Name of CA's cert file in that dir.
   #      o ssl_command           - Name of ssl utility command.
   sub ReadConfig {
       Debug("Reading the config files");
       my $perlvarref = LONCAPA::Configuration::read_conf($loncapa_config);
   
       #  Pull out the individual variables or die:
   
       # SSL Command:
   
       if($perlvarref->{SSLProgram}) {
    $ssl_command = $perlvarref->{SSLProgram};
    Debug("SSL utility program is $ssl_command");
       } 
       else {
    die "LonCAPA configuration errror: Can't read SSLProgram variable";
       }
       # Certificate directory:
      
       if($perlvarref->{lonCertificateDirectory}) {
    $loncapa_cert_dir = $perlvarref->{lonCertificateDirectory};
    Debug("Certificates will be installed in $loncapa_cert_dir");
       } 
       else {
    die "LonCAPA configuration error can't read lonCertificateDirectory variable";
   
       }
       #  Get the name of the host's certificate:
   
       if($perlvarref->{lonnetCertificate}) {
    $loncapa_hostcert_name = $perlvarref->{lonnetCertificate};
    Debug("Host's certificate will be $loncapa_hostcert_name");
       }
       else {
    die "LonCAPA configuration error: Can't read lonnetCertificate variable";
       }
       #   Get the name of the certificate authority's certificate.
   
       if($perlvarref->{lonnetCertificateAuthority}) {
    $loncapa_cacert_name = $perlvarref->{lonnetCertificateAuthority};
    Debug("CA's certificate will be $loncapa_cacert_name");
       }
       else {
    die "LonCAPA configuration error: Can't read lonnetCertificateAuthority variable";
       }
   
   
   }
   
   #  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 {  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, "<hostCertificate.pem";
       my $line;
       my $subject_found = 0;
       while ($line = <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 {}  #
   #   Create the installation script.  This will be  bash script
   #   that will install the certifiate and the CA's certificate with ownership
   #   WebUser:WebGroup and permissions 0400.  I thought about using a perl
   #   script in order to be able to get the certificate file/directory from
   #   the configuration files.  Unfortunately this is not as easy as it looks.
   #   Root has a chicken and egg problem.  In order to read the config file
   #   you need to have added the ..../lib/perl to the perl lib path. To do
   #   that correctly, you need to have read the config file to know where
   #   it is...What we will do is read our local configuration file and
   #   assume that our configuration is the same as the target's system in
   #   all respects we care about.
   # Implicit Inputs:
   #    - Bash is in /bin/bash
   #    - $loncapa_cert_dir             -  install target directory.
   #    - $loncapa_hostcert_name        -  Name of installed host cert file.
   #    - $loncapa_cacert_name          -  Name of installed ca cert file.
   #    - $loncapa_apache_user          -  username under which httpd runs.
   #    - $loncapa_apache_group         -  group under which httpd runs.
   #    - 0400                          -  install permissions.
   #    - The host's certificate is now in ./hostCertificate.pem
   #    - The CA's certificate is now in  $ca_cert_file
   #
   # Implicit Outputs:
   #    A file named CertInstall.sh
   #
   sub CreateInstallScript {
       open INSTALLER,">CertInstall.sh";
       print INSTALLER <<BASH_HEADER;
   #!/bin/bash
   #
   #    Installer for your lonCAPA certificates.  Please check the
   #    configuration variables to be sure they match your installation.
   #    Then run this script under a root shell to complete the 
   #    installation of the certificates.
   #
   # Configuration Variables:
   CERTDIR="$loncapa_cert_dir"        # Directory with your host key.
   HOSTCERT="$loncapa_hostcert_name"   # Name of host's certificate file.
   CACERT="$loncapa_cacert_name"     # Name of certifiate authority file.
   HTTPDUID="$loncapa_apache_user"     # UID of httpd.
   HTTPDGID="$loncapa_apache_group"    # GID of httpd.
   
   #   End of configuration variables.
   
   MODE=0444                           # certificates get this mode.
   HOSTCERTPATH="\$CERTDIR/\$HOSTCERT"
   CACERTPATH="\$CERTDIR/\$CACERT"
   
   #  Create the host certificate file to install:
   
   echo unpacking host certificate
   
   cat <<-HOSTCERTTEXT   >\$HOSTCERT
   BASH_HEADER
   
       #   Now copy the host certificate into the script:
   
       open HOSTCERT, "<hostCertificate.pem";
       while(my $line = <HOSTCERT>) {
    print INSTALLER $line; # Line presumably has a \n.
       }
       close HOSTCERT;
   
       #  Close the here doc, and start up the cat of the ca cert:
   
       print INSTALLER "HOSTCERTTEXT\n";
       print INSTALLER "echo unpacking CA certificate\n";
       print INSTALLER "cat <<-CACERTTEXT >\$CACERT\n";
       open  CACERT, "<$ca_cert_file";
       while(my $line = <CACERT>) {
    print INSTALLER $line;
       }
       close CACERT;
       print INSTALLER "CACERTTEXT\n";
   
       #  Ok, the script can create the two files, now it must install
       # install them >and< clean up after itself.
   
       print INSTALLER <<BASH_TRAILER;
   
   echo Installing certificates
   
   install -m \$MODE -o \$HTTPDUID -g \$HTTPDGID \$CACERT \$CACERTPATH
   install -m \$MODE -o \$HTTPDUID -g \$HTTPDGID \$HOSTCERT \$HOSTCERTPATH
   
   echo done
   
   # rm -f \$CACERT
   # rm -f \$HOSTCERT
   
   #    Do they want to restart loncapa:
   #
   
   echo In order to start running in secure mode you will need to start
   echo lonCAPA.  If you want I can do that now for you.  Otherwise,
   echo you will have to do it yourself later either by rebooting your
   echo system or by typing:
   echo
   echo /etc/init.d/loncontrol restart
   echo
   read -p "Restart loncapa now [yN]?"  yesno
   
   if [ "{\$yesno:0:1}" = "Y" ] 
   then
      /etc/init.d/loncontrol restart
   fi
   BASH_TRAILER
   
       close INSTALLER;
   }
   
 sub CreateEmail {  sub CreateEmail {
     return "Dummy message"; # Stub.      return "Dummy message"; # Stub.
Line 125  if($argc != 1) { Line 424  if($argc != 1) {
 }  }
 my $CertificateRequest = $ARGV[0];  my $CertificateRequest = $ARGV[0];
   
 my $EmailAddress = CreateCertificate($CertificateRequest);  &ReadConfig;
 CreateInstallScript;  
 my $Message = CreateEmail;  my $email_address = &CreateCertificate($CertificateRequest);
 SendEmail($EmailAddress, $Message);  Debug("CreateCertificate returned: $email_address");
 Cleanup;  
   if(!defined $email_address) {
       print STDERR "Bad or missing certificate file!!";
       Usage;
       exit -1;
   }
   
   &CreateInstallScript;
   my $Message = &CreateEmail;
   &SendEmail($email_address, $Message);
   &Cleanup;
   
 # POD documentation.  # POD documentation.

Removed from v.1.1  
changed lines
  Added in v.1.3


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>