version 1.1, 2004/05/26 10:21:23
|
version 1.7, 2004/09/17 03:00:42
|
Line 0
|
Line 1
|
|
# |
|
# $Id$ |
|
# |
|
# 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, "</dev/urandom"); |
|
sysread(RANDOM, $binaryKey, $keylength); |
|
close RANDOM; |
|
|
|
# The key must be returned in a stringified form in order to be |
|
# transmitted to the peer: |
|
|
|
my $hexdigits = $keylength*2; # Assume 8 bits/byte. |
|
my $template = "H".$hexdigits; |
|
$cipherkey = unpack($template, $binaryKey); |
|
|
|
return $cipherkey; |
|
} |
|
|
|
#------------------------------------------------------------------------ |
|
# |
|
# Name CreateKeyFile |
|
# Description Creates a private key file and writes an IDEA key into it. |
|
# |
|
# Returns |
|
# A two element list containing: |
|
# - The private key that was created |
|
# - The full path to the file that contains it. |
|
# or undef on failure. |
|
sub CreateKeyFile { |
|
|
|
# To create the file we need some perlvars to tell us where the |
|
# certificate directory. We'll make a file named localkey.$pid |
|
# there, and set the mode before writing into it. |
|
# |
|
$fileindex++; |
|
my $CertificateDir = $perlvar->{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 = <KEYFILE>; |
|
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; |
|
} |