# # $Id: lonlocal.pm,v 1.7 2004/09/17 03:00:42 albertel Exp $ # # 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 # # http://www.lon-capa.org/ # package lonlocal; # # Module that provides support for local connections between secure # lonc and secure lond. # # A local connection exchanges one-time session keys through a # file that is written in the certificate directory by lonc and # read/deleted by lond. The file is created with permissions # rw------- (0600) to prevent it from being snooped unless the system # itself has been broken. In addition the file will not be around # for very long so it will be hard to find. # use strict; # CPAN/standard modules use Crypt::IDEA; use Fcntl; # LONCAPA modules use LONCAPA::Configuration; # Global variables: my $perlvar; # Refers to the apache perlsetvar hash. my $pathsep = "/"; # Unix path seperator my $fileindex = 0; # Per process lonc uniquifier. my $lastError; # Reason for last failure. # Debugging: my $DEBUG = 0; sub Debug { my $msg = shift; if ($DEBUG) { print STDERR "$msg\n"; } } # Initialization $perlvar = LONCAPA::Configuration::read_conf('loncapa.conf'); #------------------------------------------------------------------------ # # Name CreateCipherKey # Description: Create an encryption key. # Returns: The key. # sub CreateCipherKey { my $keylength; my $binaryKey; my $cipherkey; # we'll use the output of /dev/urandom to produce our key. # On a system with decent entropy, this ought to be much more # random than all the playing that used to be done to get a key. # On a system with not so decent entropy we'll still get an ok key. # My concern with /dev/random is that we may block for an indefinite # time period...where for us decent keys are probably good enough. $keylength = IDEA::keysize(); open(RANDOM, "{lonCertificateDirectory}; my $Filename = $CertificateDir.$pathsep.".$fileindex.".$$; # If this file already exists, this is a recoverable error... we just # delete the earlier incarnation of the file. if (-w $Filename) { unlink $Filename; } # If the file still exists this is really really bad: # It most likely means someone has been devious enough to drop a key file # in place to attemp to spoof the lond. We'll fail in that case hoping # that the user looks at the log to figure out that local connections # are failing. if( -e $Filename) { $lastError = "Key file already exists after deletion probably a spoof!"; return undef; } # Now we can create the file we use sysopen in order to ensure # the file is created with the appropriate locked down permissions. if(! sysopen(KEYFILE, $Filename, O_CREAT | O_EXCL | O_WRONLY, 0600)) { $lastError = "Creation of key file failed ".$!; return undef; } # Create the key, write it to the file and close the file: my $key = CreateCipherKey(); print KEYFILE "$key\n"; close KEYFILE; return ($key, $Filename); } # Name ReadKeyFile # Description Opens the private local key file and reads the IDEA key from it. # Parameters # Name Type Description # Filename string path to key file # # NOTE: # Reading the keyfile is a one-time thing. This sub destroys the # keyfile after reading it to ensure the one-timedness of the keys they # contain!! # Returns # On success the IDEA key that was written into the key fileon failure undef. # # sub ReadKeyFile { my $Filename = shift; Debug("ReadKeyFile: $Filename"); if(! open(KEYFILE, "<$Filename")) { Debug(" Open of $Filename failed\n"); $lastError = "Key file open failed"; return undef } my $key = ; chomp($key); Debug(" Read key: $key"); close KEYFILE; unlink $Filename; # # If the filename still exists some spoofer wrote it with the wrong # permissions: # if(-e $Filename) { Debug("File did not get deleted"); $lastError = "Key file still exists after unlink"; return undef; } # # The IDEA key must be IDEA::keysize*2 characters # long. If it isn't probably someone's trying to break us by # hitting the timing hole between the file write and read... # replacing our file... of course if they read this comment they'll # be too smart to put an incorrectly sized file # my $keylen = length($key); my $rightlen= IDEA::keysize()*2; if($keylen != $rightlen) { Debug("Key is incorrect length is $keylen sb $rightlen"); $lastError = "Key file has incorrect length"; return undef; } Debug("Returning key: $key to caller"); return $key; }