--- loncom/lonlocal.pm 2004/05/26 10:21:23 1.1 +++ loncom/lonlocal.pm 2004/06/17 10:15:46 1.6 @@ -0,0 +1,217 @@ +# +# $Id: lonlocal.pm,v 1.6 2004/06/17 10:15:46 foxr 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; + 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; +}