Annotation of loncom/CrGrant.pl, revision 1.3
1.1 foxr 1: #!/usr/bin/perl
2: # The LearningOnline Network
3: # CrGrant.pl - Grant a loncapa SSL certificate.
4: #
1.3 ! foxr 5: # $Id: CrGrant.pl,v 1.2 2004/07/05 11:37:39 foxr Exp $
1.1 foxr 6: #
7: # Copyright Michigan State University Board of Trustees
8: #
9: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
10: #
11: # LON-CAPA is free software; you can redistribute it and/or modify
12: # it under the terms of the GNU General Public License as published by
13: # the Free Software Foundation; either version 2 of the License, or
14: # (at your option) any later version.
15: #
16: # LON-CAPA is distributed in the hope that it will be useful,
17: # but WITHOUT ANY WARRANTY; without even the implied warranty of
18: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19: # GNU General Public License for more details.
20: #
21: # You should have received a copy of the GNU General Public License
22: # along with LON-CAPA; if not, write to the Free Software
23: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24: #
25: # /home/httpd/html/adm/gpl.txt
26: #
27:
28:
29: # http://www.lon-capa.org/
30: #
31: # This script operates on a certificate request that has been
32: # extracted from the attachment sent to the loncapa certificate
33: # administrator and:
34: #
35: # 1. Creates an ssl certificate corresponding to the request.
36: # 2. Constructs an installation script that will install
37: # the certificate along with the certificate authority's
38: # certificate in a loncapa system.
39: # 3. Constructs an email which contains a cover letter
40: # describing what to do with the attachment, and an
41: # attachment that consists of the installation script
42: # created in step 2.
43: # 4. Emails the message to the email address in the certificate
44: # request.
45: #
46: # There are some assumptions we need to make in order to
47: # get this all to work:
48: # - The certificate authority is installed on a
49: # loncapa system with configuration files that specify
50: # the same certificate directory and certificate filenames
51: # as the target system (otherwise we can't generate the
52: # installation script).
53: # - The loncapa certificate authority configuration file is
54: # $SSLDir/loncapaca.cnf and that it specifies that:
55: # o The certificate authority files are in $SSLDir/loncapaca
56: # o The certificate authority certificate is in:
57: # $SSLDir/loncapaca/cacert.pem
1.2 foxr 58: # o Only one instance of this script will be run at a time in
59: # this directory.
1.1 foxr 60: # o The person that runs this script knows the passphrase
61: # for the loncapa certificate authority's private key
62: # which remains encrypted for security reasons.
63: #
64: #
65:
66: # Import section:
67:
68: use strict;
1.3 ! foxr 69: use lib '/home/httpd/lib/perl'; # An assumption!!!
1.1 foxr 70: use MIME::Entity;
71: use LONCAPA::Configuration;
72:
73:
74:
75: # Global variable declarations
76:
1.3 ! foxr 77:
1.2 foxr 78: my $ssl_dir = "/usr/share/ssl"; # Where ssl config files etc. live
1.3 ! foxr 79: my $ca_cert_file = $ssl_dir."/loncapaca/cacert.pem"; # CA's certificate file.
1.2 foxr 80: my $ca_config_file= $ssl_dir."/loncapaca.cnf"; # CA's config file.
1.1 foxr 81:
1.3 ! foxr 82:
! 83: # LONCAPA Configuration global variables:
! 84:
! 85: # Items read from our configuration file.
! 86:
! 87: my $ssl_command = "/usr/bin/openssl "; # Command to run openssl.
! 88: my $loncapa_cert_dir; # Name of target cert dir (from config)
! 89: my $loncapa_hostcert_name; # Name of host's signed cert file (config)
! 90: my $loncapa_cacert_name; # Name of the CA's certificate file (config)
! 91:
! 92: # Items I just need to know:
! 93:
! 94: my $loncapa_config = "loncapa.conf"; # User's override config file.
! 95: my $loncapa_apache_user = 'www'; # Name of apache daemon's user
! 96: my $loncapa_apache_group = 'www'; # Name of apache daemon's group
! 97:
! 98:
1.1 foxr 99:
100: # Debug/log support
101:
102: my $DEBUG=1;
103:
104: sub Debug {
105: my $msg = shift;
106: if($DEBUG) {
107: print STDERR "$msg\n";
108: }
109: }
110: # Support subs:
111:
1.2 foxr 112: #
113: # Print out program usage.
114: #
115: # Side effects:
116: # Output goes to stderr.
117: #
118: sub Usage {
119: print STDERR << "USAGE";
120:
121: Usage:
122: CrGrant.pl requestfile.pem
1.1 foxr 123:
1.2 foxr 124: Where:
125: requestfile.pem is a PEM formatted certificate extracted from an email
126: to the LonCAPA certificate manager.
127: USAGE
128:
129: }
1.3 ! foxr 130: #
! 131: # Read the loncapa configuration file and pull out the items
! 132: # we need:
! 133: #
! 134: # Implicit inputs:
! 135: # $loncapa_config - The name of the auxilliary config file.
! 136: # Side effects:
! 137: # - On failure exits with an error message.
! 138: # - On success set the following variables:
! 139: # o loncapa_cert_dir - Path to certificates.
! 140: # o loncapa_hostcert_name - Name of host's cert file in that dir
! 141: # o loncapa_cacert_name - Name of CA's cert file in that dir.
! 142: # o ssl_command - Name of ssl utility command.
! 143: sub ReadConfig {
! 144: Debug("Reading the config files");
! 145: my $perlvarref = LONCAPA::Configuration::read_conf($loncapa_config);
! 146:
! 147: # Pull out the individual variables or die:
! 148:
! 149: # SSL Command:
! 150:
! 151: if($perlvarref->{SSLProgram}) {
! 152: $ssl_command = $perlvarref->{SSLProgram};
! 153: Debug("SSL utility program is $ssl_command");
! 154: }
! 155: else {
! 156: die "LonCAPA configuration errror: Can't read SSLProgram variable";
! 157: }
! 158: # Certificate directory:
! 159:
! 160: if($perlvarref->{lonCertificateDirectory}) {
! 161: $loncapa_cert_dir = $perlvarref->{lonCertificateDirectory};
! 162: Debug("Certificates will be installed in $loncapa_cert_dir");
! 163: }
! 164: else {
! 165: die "LonCAPA configuration error can't read lonCertificateDirectory variable";
! 166:
! 167: }
! 168: # Get the name of the host's certificate:
! 169:
! 170: if($perlvarref->{lonnetCertificate}) {
! 171: $loncapa_hostcert_name = $perlvarref->{lonnetCertificate};
! 172: Debug("Host's certificate will be $loncapa_hostcert_name");
! 173: }
! 174: else {
! 175: die "LonCAPA configuration error: Can't read lonnetCertificate variable";
! 176: }
! 177: # Get the name of the certificate authority's certificate.
! 178:
! 179: if($perlvarref->{lonnetCertificateAuthority}) {
! 180: $loncapa_cacert_name = $perlvarref->{lonnetCertificateAuthority};
! 181: Debug("CA's certificate will be $loncapa_cacert_name");
! 182: }
! 183: else {
! 184: die "LonCAPA configuration error: Can't read lonnetCertificateAuthority variable";
! 185: }
! 186:
! 187:
! 188: }
! 189:
1.2 foxr 190: # Create a certificate from the request file. The certificate
191: # is used, in conjunction with the openssl command with the
192: # certificate authority configuration to produce a certificate
193: # file.
194: #
195: # The certificate is parsed to determine the email address
196: # of the requestor, which is returned to the caller.
197: #
198: #Parameters:
199: # request_file - Name of the file containing the certificate request.
200: #Returns:
201: # If the request file exists and is able to produce a certificate
202: # the email address of the requester is returned to the caller.
203: # If not, undef is returned.
204: #
1.1 foxr 205: sub CreateCertificate {
1.2 foxr 206: my ($request_file) = @_;
207:
208: Debug("CreateCertificate");
209:
210: if(!(-e $request_file)) {
211: Debug("Certificate file $request_file does not exist");
212: return undef;
213: }
214: Debug("Certificate file $request_file exists");
215:
216: # Create the certificate: The status of the openssl command
217: # is used to determine if the certificate succeeded:
218:
219: my $create_command = $ssl_command." ca -config ".$ca_config_file
220: ." -in ".$request_file
221: ." -out hostCertificate.pem";
222: my $status = system($create_command);
223: if($status) {
224: Debug("openssl ca failed");
225: print STDERR "Certificate generation failed... probably bad";
226: print STDERR " request file!\n";
227: return undef;
228: }
229: Debug("openssl ca succeeded");
230:
231: # Now we have a shining new signed certificate in ./hostCertificate.pem
232: # we parse it to get the email address to which the certificate should
233: # be emailed.
234: # The certificate's return email address will be in the Subject line:
235: #
236:
237: Debug("Parsing certificate file for Subject:");
238: open CERTIFICATE, "<hostCertificate.pem";
239: my $line;
240: my $subject_found = 0;
241: while ($line = <CERTIFICATE>) {
242: Debug("Line = $line");
243: if($line =~ /Subject:/) {
244: Debug("Found Subject: in $line");
245: $subject_found =1;
246: last;
247: }
248: }
249: close CERTIFICATE;
250:
251: if(!$subject_found) {
252: Debug("Did not find Subject line in cert");
253: print STDERR "Output certificate parse failed: no Subject:\n";
254: return undef;
255: }
256: # The subject line contains an Email= string amidst the other stuff.
257: # First break in to comma separated stuff, then locate the piece that
258: # contains /Email=
259:
260: my @subject_fields = split(/,/, $line);
261: my $email_found = 0;
262: my $element;
263: my $email_element;
264: Debug("Parsing subject line for Email=");
265: foreach $element (@subject_fields) {
266: $email_element = $element;
267: Debug("Parsing $element");
268: if($element =~ /\/Email=/) {
269: Debug("Found /Email=");
270: $email_found = 1;
271: last;
272: }
273: }
274: if(!$email_found) {
275: Debug("Failed to fine Email=");
276: print STDERR "Unable to find line with /Email= in cert. Subject\n";
277: return undef;
278: }
279:
280: # The piece we found must first be split at the /
281: # to isolate the Email= part and then that part at the = to isolate
282: # the address:
283:
284: Debug("Splitting $email_element at /");
285: my ($junk, $email) = split(/\//, $email_element);
286: Debug("Email part is $email");
287: my ($junk, $address) = split(/=/, $email);
288: Debug("CreateCertificate Returning $address to caller");
289:
290: return $address;
1.1 foxr 291:
292: }
1.3 ! foxr 293: #
! 294: # Create the installation script. This will be bash script
! 295: # that will install the certifiate and the CA's certificate with ownership
! 296: # WebUser:WebGroup and permissions 0400. I thought about using a perl
! 297: # script in order to be able to get the certificate file/directory from
! 298: # the configuration files. Unfortunately this is not as easy as it looks.
! 299: # Root has a chicken and egg problem. In order to read the config file
! 300: # you need to have added the ..../lib/perl to the perl lib path. To do
! 301: # that correctly, you need to have read the config file to know where
! 302: # it is...What we will do is read our local configuration file and
! 303: # assume that our configuration is the same as the target's system in
! 304: # all respects we care about.
! 305: # Implicit Inputs:
! 306: # - Bash is in /bin/bash
! 307: # - $loncapa_cert_dir - install target directory.
! 308: # - $loncapa_hostcert_name - Name of installed host cert file.
! 309: # - $loncapa_cacert_name - Name of installed ca cert file.
! 310: # - $loncapa_apache_user - username under which httpd runs.
! 311: # - $loncapa_apache_group - group under which httpd runs.
! 312: # - 0400 - install permissions.
! 313: # - The host's certificate is now in ./hostCertificate.pem
! 314: # - The CA's certificate is now in $ca_cert_file
! 315: #
! 316: # Implicit Outputs:
! 317: # A file named CertInstall.sh
! 318: #
! 319: sub CreateInstallScript {
! 320: open INSTALLER,">CertInstall.sh";
! 321: print INSTALLER <<BASH_HEADER;
! 322: #!/bin/bash
! 323: #
! 324: # Installer for your lonCAPA certificates. Please check the
! 325: # configuration variables to be sure they match your installation.
! 326: # Then run this script under a root shell to complete the
! 327: # installation of the certificates.
! 328: #
! 329: # Configuration Variables:
! 330: CERTDIR="$loncapa_cert_dir" # Directory with your host key.
! 331: HOSTCERT="$loncapa_hostcert_name" # Name of host's certificate file.
! 332: CACERT="$loncapa_cacert_name" # Name of certifiate authority file.
! 333: HTTPDUID="$loncapa_apache_user" # UID of httpd.
! 334: HTTPDGID="$loncapa_apache_group" # GID of httpd.
! 335:
! 336: # End of configuration variables.
! 337:
! 338: MODE=0444 # certificates get this mode.
! 339: HOSTCERTPATH="\$CERTDIR/\$HOSTCERT"
! 340: CACERTPATH="\$CERTDIR/\$CACERT"
! 341:
! 342: # Create the host certificate file to install:
! 343:
! 344: echo unpacking host certificate
! 345:
! 346: cat <<-HOSTCERTTEXT >\$HOSTCERT
! 347: BASH_HEADER
! 348:
! 349: # Now copy the host certificate into the script:
! 350:
! 351: open HOSTCERT, "<hostCertificate.pem";
! 352: while(my $line = <HOSTCERT>) {
! 353: print INSTALLER $line; # Line presumably has a \n.
! 354: }
! 355: close HOSTCERT;
! 356:
! 357: # Close the here doc, and start up the cat of the ca cert:
! 358:
! 359: print INSTALLER "HOSTCERTTEXT\n";
! 360: print INSTALLER "echo unpacking CA certificate\n";
! 361: print INSTALLER "cat <<-CACERTTEXT >\$CACERT\n";
! 362: open CACERT, "<$ca_cert_file";
! 363: while(my $line = <CACERT>) {
! 364: print INSTALLER $line;
! 365: }
! 366: close CACERT;
! 367: print INSTALLER "CACERTTEXT\n";
! 368:
! 369: # Ok, the script can create the two files, now it must install
! 370: # install them >and< clean up after itself.
! 371:
! 372: print INSTALLER <<BASH_TRAILER;
! 373:
! 374: echo Installing certificates
! 375:
! 376: install -m \$MODE -o \$HTTPDUID -g \$HTTPDGID \$CACERT \$CACERTPATH
! 377: install -m \$MODE -o \$HTTPDUID -g \$HTTPDGID \$HOSTCERT \$HOSTCERTPATH
! 378:
! 379: echo done
! 380:
! 381: # rm -f \$CACERT
! 382: # rm -f \$HOSTCERT
! 383:
! 384: # Do they want to restart loncapa:
! 385: #
! 386:
! 387: echo In order to start running in secure mode you will need to start
! 388: echo lonCAPA. If you want I can do that now for you. Otherwise,
! 389: echo you will have to do it yourself later either by rebooting your
! 390: echo system or by typing:
! 391: echo
! 392: echo /etc/init.d/loncontrol restart
! 393: echo
! 394: read -p "Restart loncapa now [yN]?" yesno
! 395:
! 396: if [ "{\$yesno:0:1}" = "Y" ]
! 397: then
! 398: /etc/init.d/loncontrol restart
! 399: fi
! 400: BASH_TRAILER
! 401:
! 402: close INSTALLER;
! 403: }
1.1 foxr 404:
405: sub CreateEmail {
406: return "Dummy message"; # Stub.
407: }
408:
409: sub SendEmail {
410: my ($EmailAddress, $Message) = @_;
411: }
412: sub Cleanup {}
413:
414:
415: # Program entry point
416: # The usage is:
417: # CrGrant.pl {request_file}
418: #
419:
420: my $argc = @ARGV; # Count number of command parameters.
421: if($argc != 1) {
422: Usage;
423: exit -1;
424: }
425: my $CertificateRequest = $ARGV[0];
426:
1.3 ! foxr 427: &ReadConfig;
! 428:
! 429: my $email_address = &CreateCertificate($CertificateRequest);
! 430: Debug("CreateCertificate returned: $email_address");
1.2 foxr 431:
432: if(!defined $email_address) {
433: print STDERR "Bad or missing certificate file!!";
434: Usage;
435: exit -1;
436: }
437:
1.3 ! foxr 438: &CreateInstallScript;
! 439: my $Message = &CreateEmail;
! 440: &SendEmail($email_address, $Message);
! 441: &Cleanup;
1.1 foxr 442:
443: # POD documentation.
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>