--- loncom/lonssl.pm 2004/06/01 09:53:44 1.7 +++ loncom/lonssl.pm 2004/06/17 09:27:38 1.8 @@ -1,5 +1,5 @@ # -# $Id: lonssl.pm,v 1.7 2004/06/01 09:53:44 foxr Exp $ +# $Id: lonssl.pm,v 1.8 2004/06/17 09:27:38 foxr Exp $ # # Copyright Michigan State University Board of Trustees # @@ -38,6 +38,9 @@ use strict; use IO::Socket::INET; use IO::Socket::SSL; +use Fcntl; +use POSIX; + # Loncapa modules: use LONCAPA::Configuration; @@ -55,6 +58,39 @@ my $pathsep = "/"; # We're on unix afte $perlvar = LONCAPA::Configuration::read_conf('loncapa.conf'); +my $lasterror=""; + + +sub LastError { + return $lasterror; +} + +#------------------------------------------------------------------------- +# Name SetFdBlocking - +# Turn blocking mode on on the file handle. This is required for +# SSL key negotiation. +# +# Parameters: +# Handle - Reference to the handle to modify. +# Returns: +# prior flag settings. +# +sub SetFdBlocking { + print STDERR "SetFdBlocking called \n"; + my $Handle = shift; + + + + my $flags = fcntl($Handle, F_GETFL, 0); + if(!$flags) { + print STDERR "SetBLocking fcntl get faild $!\n"; + } + my $newflags = $flags & (~ O_NONBLOCK); # Turn off O_NONBLOCK... + if(!fcntl($Handle, F_SETFL, $newflags)) { + print STDERR "Can't set non block mode $!\n"; + } + return $flags; +} #-------------------------------------------------------------------------- # @@ -73,6 +109,8 @@ $perlvar = LONCAPA::Configuration::read_ # - Reference to an SSL socket on success # - undef on failure. Reason for failure can be interrogated from # IO::Socket::SSL +# Side effects: socket is left in blocking mode!! +# sub PromoteClientSocket { my ($PlaintextSocket, @@ -81,18 +119,29 @@ sub PromoteClientSocket { $KeyFile) = @_; + print STDERR "Client promotion using key: $KeyFile, Cert: $MyCert, CA: $CACert\n"; + # To create the ssl socket we need to duplicate the existing # socket. Otherwise closing the ssl socket will close the plaintext socket - # too: - - open (DUPLICATE, "+>$PlaintextSocket"); + # too. We also must flip into blocking mode for the duration of the + # ssl negotiation phase.. the caller will have to flip to non block if + # that's what they want + + my $oldflags = SetFdBlocking($PlaintextSocket); + my $dupfno = fcntl($PlaintextSocket, F_DUPFD, 0); + print STDERR "Client promotion got dup = $dupfno\n"; + - my $client = IO::Socket::SSL->new_from_fd(fileno(DUPLICATE), + my $client = IO::Socket::SSL->new_from_fd($dupfno, SSL_user_cert => 1, SSL_key_file => $KeyFile, SSL_cert_file => $MyCert, - SSL_ca_fie => $$CACert); + SSL_ca_fie => $CACert); + if(!$client) { + $lasterror = IO::Socket::SSL::errstr(); + return undef; + } return $client; # Undef if the client negotiation fails. } @@ -112,6 +161,9 @@ sub PromoteClientSocket { # - Reference to an SSL socket on success # - undef on failure. Reason for failure can be interrogated from # IO::Socket::SSL +# Side Effects: +# Socket is left in blocking mode!!! +# sub PromoteServerSocket { my ($PlaintextSocket, $CACert, @@ -124,14 +176,24 @@ sub PromoteServerSocket { # socket. Otherwise closing the ssl socket will close the plaintext socket # too: - open (DUPLICATE, "+>$PlaintextSocket"); - - my $client = IO::Socket::SSL->new_from_fd(fileno(DUPLICATE), + print STDERR "Server promotion: Key = $KeyFile, Cert $MyCert CA $CACert\n"; + + my $oldflags = SetFdBlocking($PlaintextSocket); + my $dupfno = fcntl($PlaintextSocket, F_DUPFD, 0); + if (!$dupfno) { + print STDERR "dup failed: $!\n"; + } + print STDERR " Fileno = $dupfno\n"; + my $client = IO::Socket::SSL->new_from_fd($dupfno, SSL_server => 1, # Server role. SSL_user_cert => 1, SSL_key_file => $KeyFile, SSL_cert_file => $MyCert, - SSL_ca_fie => $$CACert); + SSL_ca_fie => $CACert); + if(!$client) { + $lasterror = IO::Socket::SSL::errstr(); + return undef; + } return $client; } @@ -170,7 +232,7 @@ sub GetPeerCertificate { my $CertOwner = $SSLSocket->peer_certificate("owner"); my $CertCA = $SSLSocket->peer_certificate("authority"); - return \($CertCA, $CertOwner); + return ($CertCA, $CertOwner); } #---------------------------------------------------------------------------- # @@ -193,6 +255,8 @@ sub CertificateFile { # Ensure the existence of these variables: if((!$CertificateDir) || (!$CaFilename) || (!$CertFilename)) { + $lasterror = "Missing info: dir: $CertificateDir CA: $CaFilename " + ."Cert: $CertFilename"; return undef; } @@ -203,12 +267,14 @@ sub CertificateFile { my $CertFilename = $CertificateDir.$pathsep.$CertFilename; if((! -r $CaFilename) || (! -r $CertFilename)) { + $lasterror = "CA file $CaFilename or Cert File: $CertFilename " + ."not readable"; return undef; } # Everything works fine!! - return \($CaFilename, $CertFilename); + return ($CaFilename, $CertFilename); } #------------------------------------------------------------------------ @@ -230,6 +296,8 @@ sub KeyFile { # Ensure the variables exist: if((!$CertificateDir) || (!$KeyFilename)) { + $lasterror = "Missing parameter dir: $CertificateDir " + ."key: $KeyFilename"; return undef; } @@ -238,6 +306,7 @@ sub KeyFile { my $KeyFilename = $CertificateDir.$pathsep.$KeyFilename; if(! (-r $KeyFilename)) { + $lasterror = "Unreadable key file $KeyFilename"; return undef; }