File:  [LON-CAPA] / loncom / lonlocal.pm
Revision 1.3: download - view: text, annotated - select for diffs
Fri May 28 10:20:03 2004 UTC (19 years, 9 months ago) by foxr
Branches: MAIN
CVS tags: HEAD
Good compile of the module

#
# $Id: lonlocal.pm,v 1.3 2004/05/28 10:20:03 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 English;
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.


# Initialization

$perlvar = LONCAPA::Configuration::read_conf('loncapa.conf');


#------------------------------------------------------------------------
#
# Name          BuildKey
# Description:  Create an encryption key.
# Returns:      The key.
#
sub CreateCipherKey {

    my $keylength;
    my $binaryKey;
    my $cipherkey;
    
    # we'll use the output of /dev/random 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.
    #
    
    $keylength   =  IDEA::keysize();
    open(RANDOM, "</dev/random");
    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.".$PID;

    # 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 ".$ERRNO;
	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;

    if(! open(KEYFILE, "<$Filename")) {
	$lastError = "Key file open failed";
	return undef
    }
    my $key = <KEYFILE>;
    chomp;
    close KEYFILE;
    unlink $Filename;
    #
    #  If the filename still exists some spoofer wrote it with the wrong
    #  permissions:
    #
    if(-e $Filename) {
	$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
    #
    if(length($key) != IDEA::keysize*2) {
	$lastError = "Key file has incorrect length";
	return undef;
    }
    return $key;   
}

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