Diff for /loncom/LondConnection.pm between versions 1.46 and 1.62

version 1.46, 2007/04/10 23:15:20 version 1.62, 2018/12/14 02:05:38
Line 40  use LONCAPA::lonlocal; Line 40  use LONCAPA::lonlocal;
 use LONCAPA::lonssl;  use LONCAPA::lonssl;
   
   
   
   
 my $DebugLevel=0;  my $DebugLevel=0;
 my %perlvar;  my %perlvar;
   my %secureconf;
   my %badcerts;
   my %hosttypes;
   my %crlchecked;
 my $InsecureOk;  my $InsecureOk;
   
 #  #
Line 70  sub ReadConfig { Line 72  sub ReadConfig {
     my $perlvarref = read_conf('loncapa.conf');      my $perlvarref = read_conf('loncapa.conf');
     %perlvar    = %{$perlvarref};      %perlvar    = %{$perlvarref};
     $ConfigRead = 1;      $ConfigRead = 1;
       
     $InsecureOk = $perlvar{loncAllowInsecure};      $InsecureOk = $perlvar{loncAllowInsecure};
   
       unless (lonssl::Read_Connect_Config(\%secureconf,\%perlvar) eq 'ok') {
           Debug(1,"Failed to retrieve secureconf hash.\n");
       }
       unless (lonssl::Read_Host_Types(\%hosttypes,\%perlvar) eq 'ok') {
           Debug(1,"Failed to retrieve hosttypes hash.\n");
       }
       %badcerts = ();
       %crlchecked = ();
   }
   
   sub ResetReadConfig {
       $ConfigRead = 0;
 }  }
   
 sub Debug {  sub Debug {
Line 150  host the remote lond is on. This host is Line 165  host the remote lond is on. This host is
   
  port number the remote lond is listening on.   port number the remote lond is listening on.
   
   =item lonid
   
    lonid of the remote lond is listening on.
   
   =item deflonid
   
    default lonhostID of the remote lond is listening on.
   
 =cut  =cut
   
 sub new {  sub new {
     my ($class, $DnsName, $Port, $lonid) = @_;      my ($class, $DnsName, $Port, $lonid, $deflonid, $loncaparev) = @_;
   
     if (!$ConfigRead) {      if (!$ConfigRead) {
  ReadConfig();   ReadConfig();
  $ConfigRead = 1;   $ConfigRead = 1;
     }      }
     &Debug(4,$class."::new( ".$DnsName.",".$Port.",".$lonid.")\n");      &Debug(4,$class."::new( ".$DnsName.",".$Port.",".$lonid.",".$deflonid.",".$loncaparev.")\n");
   
       my ($conntype,$gotconninfo,$allowinsecure);
       if ((ref($secureconf{'connto'}) eq 'HASH') &&
           (exists($hosttypes{$lonid}))) {
           $conntype = $secureconf{'connto'}{$hosttypes{$lonid}};
           if ($conntype ne '') {
               if ($conntype ne 'req') {
                   $allowinsecure = 1;
               }
               $gotconninfo = 1;
           }
       }
       unless ($gotconninfo) {
           $allowinsecure = $InsecureOk;
       }
   
     # The host must map to an entry in the hosts table:      # The host must map to an entry in the hosts table:
     #  We connect to the dns host that corresponds to that      #  We connect to the dns host that corresponds to that
Line 173  sub new { Line 211  sub new {
     # Now create the object...      # Now create the object...
     my $self     = { Host               => $DnsName,      my $self     = { Host               => $DnsName,
                      LoncapaHim         => $lonid,                       LoncapaHim         => $lonid,
                        LoncapaDefid       => $deflonid,
                        LoncapaRev         => $loncaparev, 
                      Port               => $Port,                       Port               => $Port,
                      State              => "Initialized",                       State              => "Initialized",
      AuthenticationMode => "",       AuthenticationMode => "",
        InsecureOK         => $allowinsecure,
                      TransactionRequest => "",                       TransactionRequest => "",
                      TransactionReply   => "",                       TransactionReply   => "",
                      NextRequest        => "",                       NextRequest        => "",
Line 189  sub new { Line 230  sub new {
      LocalKeyFile       => "",       LocalKeyFile       => "",
                      CipherKey          => "",                       CipherKey          => "",
                      LondVersion        => "Unknown",                       LondVersion        => "Unknown",
                      Cipher             => undef};                       Cipher             => undef,
        ClientData         => undef};
     bless($self, $class);      bless($self, $class);
     unless ($self->{Socket} = IO::Socket::INET->new(PeerHost => $self->{Host},      unless ($self->{Socket} = IO::Socket::INET->new(PeerHost => $self->{Host},
        PeerPort => $self->{Port},         PeerPort => $self->{Port},
Line 200  sub new { Line 242  sub new {
  return undef; # Inidicates the socket could not be made.   return undef; # Inidicates the socket could not be made.
     }      }
     my $socket = $self->{Socket}; # For local use only.      my $socket = $self->{Socket}; # For local use only.
       $socket->sockopt(SO_KEEPALIVE, 1); # Turn on keepalive probes when idle.
     #  If we are local, we'll first try local auth mode, otherwise, we'll try      #  If we are local, we'll first try local auth mode, otherwise, we'll try
     #  the ssl auth mode:      #  the ssl auth mode:
   
Line 214  sub new { Line 257  sub new {
  #  allowed...else give up right away.   #  allowed...else give up right away.
   
  if(!(defined $key) || !(defined $keyfile)) {   if(!(defined $key) || !(defined $keyfile)) {
     if($InsecureOk) {              my $canconnect = 0;
               if (ref($secureconf{'connto'}) eq 'HASH') {
                   unless ($secureconf{'connto'}->{'dom'} eq 'req') {
                       $canconnect = 1;
                   }
               } else {
                   $canconnect = $InsecureOk;
               }
       if ($canconnect) {
  $self->{AuthenticationMode} = "insecure";   $self->{AuthenticationMode} = "insecure";
  $self->{TransactionRequest} = "init\n";   $self->{TransactionRequest} = "init\n";
     }       } 
Line 237  sub new { Line 288  sub new {
   
  my ($ca, $cert) = lonssl::CertificateFile;   my ($ca, $cert) = lonssl::CertificateFile;
  my $sslkeyfile  = lonssl::KeyFile;   my $sslkeyfile  = lonssl::KeyFile;
           my $badcertfile = lonssl::has_badcert_file($self->{LoncapaHim});
           my ($loncaparev) = ($perlvar{'lonVersion'} =~ /^[\'\"]?([\w.\-]+)[\'\"]?$/);
   
  if((defined $ca)  && (defined $cert) && (defined $sslkeyfile)) {   if (($conntype ne 'no') && (defined($ca)) && (defined($cert)) && (defined($sslkeyfile)) &&
               (!exists($badcerts{$self->{LoncapaHim}})) && !$badcertfile) {
     $self->{AuthenticationMode} = "ssl";      $self->{AuthenticationMode} = "ssl";
     $self->{TransactionRequest} = "init:ssl\n";      $self->{TransactionRequest} = "init:ssl:$loncaparev\n";
    } elsif ($self->{InsecureOK}) {
       # Allowed to do insecure:
       $self->{AuthenticationMode} = "insecure";
       $self->{TransactionRequest} = "init::$loncaparev\n";
  } else {   } else {
     if($InsecureOk) { # Allowed to do insecure:      # Not allowed to do insecure...
  $self->{AuthenticationMode} = "insecure";      $socket->close;
  $self->{TransactionRequest} = "init\n";      return undef;
     }  
     else { # Not allowed to do insecure...  
  $socket->close;  
  return undef;  
     }  
  }   }
     }      }
   
Line 340  sub Readable { Line 392  sub Readable {
  $self->Transition("Disconnected");   $self->Transition("Disconnected");
  return -1;   return -1;
     }      }
       # If we actually got data, reset the timeout.
   
       if (length $data) {
    $self->{TimeoutRemaining}   = $self->{TimeoutValue}; # getting data resets the timeout period.
       }
     #  Append the data to the buffer.  And figure out if the read is done:      #  Append the data to the buffer.  And figure out if the read is done:
   
     &Debug(9,"Received from host: ".$data);      &Debug(9,"Received from host: ".$data);
Line 392  sub Readable { Line 449  sub Readable {
     }      }
     elsif ($ConnectionMode eq "ssl") {      elsif ($ConnectionMode eq "ssl") {
  if($Response =~ /^ok:ssl/) {     # Good ssl...   if($Response =~ /^ok:ssl/) {     # Good ssl...
     if($self->ExchangeKeysViaSSL()) { # Success skip to vsn stuff      my $sslresult = $self->ExchangeKeysViaSSL();
                       if ($sslresult == 1) { # Success skip to vsn stuff
  # Need to reset to non blocking:   # Need to reset to non blocking:
   
  my $flags = fcntl($socket, F_GETFL, 0);   my $flags = fcntl($socket, F_GETFL, 0);
  fcntl($socket, F_SETFL, $flags | O_NONBLOCK);   fcntl($socket, F_SETFL, $flags | O_NONBLOCK);
  $self->ToVersionRequest();   $self->ToVersionRequest();
  return 0;   return 0;
     }      } 
     else {         # Failed in ssl exchange.      else { # Failed in ssl exchange.
           if (($sslresult == -1) && (lonssl::LastError == -1) && ($self->{InsecureOK})) {
                               my $badcertdir = &lonssl::BadCertDir();
                               if (($badcertdir) && $self->{LoncapaHim}) {
                                   if (open(my $fh,'>',"$badcertdir/".$self->{LoncapaHim})) {
                                       close($fh);
                                   }
                               }
       $badcerts{$self->{LoncapaHim}} = 1;
                               &Debug(3,"SSL verification failed: close socket and initiate insecure connection");
                               $self->Transition("ReInitNoSSL");
                               $socket->close;
                               return -1;
    }
  &Debug(3,"init:ssl failed key negotiation!");   &Debug(3,"init:ssl failed key negotiation!");
  $self->Transition("Disconnected");   $self->Transition("Disconnected");
  $socket->close;   $socket->close;
  return -1;   return -1;
     }                      }
  }    } 
  elsif ($Response =~ /^[0-9]+/) { # Old style lond.   elsif ($Response =~ /^[0-9]+/) { # Old style lond.
     return $self->CompleteInsecure();      return $self->CompleteInsecure();
Line 470  sub Readable { Line 541  sub Readable {
     }      }
  } elsif ($self->{State}  eq "ReceivingKey") {   } elsif ($self->{State}  eq "ReceivingKey") {
     my $buildkey = $self->{TransactionReply};      my $buildkey = $self->{TransactionReply};
               chomp($buildkey);
     my $key = $self->{LoncapaHim}.$perlvar{'lonHostID'};      my $key = $self->{LoncapaHim}.$perlvar{'lonHostID'};
     $key=~tr/a-z/A-Z/;      $key=~tr/a-z/A-Z/;
     $key=~tr/G-P/0-9/;      $key=~tr/G-P/0-9/;
Line 501  sub Readable { Line 573  sub Readable {
  $self->{InformWritable}     = 1;   $self->{InformWritable}     = 1;
  $self->{InformReadable}     = 0;   $self->{InformReadable}     = 0;
  $self->{Timeoutable}        = 1;   $self->{Timeoutable}        = 1;
  $self->{TimeoutRemaining}   = $self->{TimeoutValue};  
  $self->Transition("SendingRequest");   $self->Transition("SendingRequest");
  return 0;   return 0;
     } else {      } else {
Line 563  sub Writable { Line 634  sub Writable {
  ($errno == POSIX::EAGAIN)         ||   ($errno == POSIX::EAGAIN)         ||
  ($errno == POSIX::EINTR)          ||   ($errno == POSIX::EINTR)          ||
  ($errno ==  0)) {   ($errno ==  0)) {
    $self->{TimeoutRemaining} = $self->{TimeoutValue};
  substr($self->{TransactionRequest}, 0, $nwritten) = ""; # rmv written part   substr($self->{TransactionRequest}, 0, $nwritten) = ""; # rmv written part
       if(length $self->{TransactionRequest} == 0) {   if(length $self->{TransactionRequest} == 0) {
          $self->{InformWritable} = 0;      $self->{InformWritable} = 0;
          $self->{InformReadable} = 1;      $self->{InformReadable} = 1;
          $self->{TransactionReply} = '';      $self->{TransactionReply} = '';
          #      #
          # Figure out the next state:      # Figure out the next state:
          #      #
          if($self->{State} eq "Connected") {      if($self->{State} eq "Connected") {
             $self->Transition("Initialized");   $self->Transition("Initialized");
          } elsif($self->{State} eq "ChallengeReceived") {      } elsif($self->{State} eq "ChallengeReceived") {
             $self->Transition("ChallengeReplied");   $self->Transition("ChallengeReplied");
          } elsif($self->{State} eq "RequestingVersion") {      } elsif($self->{State} eq "RequestingVersion") {
             $self->Transition("ReadingVersionString");   $self->Transition("ReadingVersionString");
          } elsif ($self->{State} eq "SetHost") {      } elsif ($self->{State} eq "SetHost") {
             $self->Transition("HostSet");   $self->Transition("HostSet");
          } elsif($self->{State} eq "RequestingKey") {      } elsif($self->{State} eq "RequestingKey") {
             $self->Transition("ReceivingKey");   $self->Transition("ReceivingKey");
 #            $self->{InformWritable} = 0;  #            $self->{InformWritable} = 0;
 #            $self->{InformReadable} = 1;  #            $self->{InformReadable} = 1;
 #            $self->{TransactionReply} = '';  #            $self->{TransactionReply} = '';
          } elsif ($self->{State} eq "SendingRequest") {      } elsif ($self->{State} eq "SendingRequest") {
             $self->Transition("ReceivingReply");   $self->Transition("ReceivingReply");
             $self->{TimeoutRemaining} = $self->{TimeoutValue};   $self->{TimeoutRemaining} = $self->{TimeoutValue};
          } elsif ($self->{State} eq "Disconnected") {      } elsif ($self->{State} eq "Disconnected") {
             return -1;   return -1;
          }      }
          return 0;      return 0;
       }   }
    } else { # The write failed (e.g. partner disconnected).      } else { # The write failed (e.g. partner disconnected).
       $self->Transition("Disconnected");   $self->Transition("Disconnected");
       $socket->close();   $socket->close();
       return -1;   return -1;
    }      }
       
 }  }
 =pod  =pod
   
Line 744  sub Shutdown { Line 816  sub Shutdown {
     $socket->shutdown(2);      $socket->shutdown(2);
  }   }
     }      }
       $self->{Timeoutable}   = 0; # Shutdown sockets can't timeout.
 }  }
   
 =pod  =pod
Line 994  sub CreateCipher { Line 1067  sub CreateCipher {
 sub ExchangeKeysViaSSL {  sub ExchangeKeysViaSSL {
     my $self   = shift;      my $self   = shift;
     my $socket = $self->{Socket};      my $socket = $self->{Socket};
       my $peer = $self->{LoncapaHim};
       my $peerdef = $self->{LoncapaDefid};
       my $loncaparev = $self->{LoncapaRev};
   
     #  Get our signed certificate, the certificate authority's       #  Get our signed certificate, the certificate authority's 
     #  certificate and our private key file.  All of these      #  certificate and our private key file.  All of these
Line 1002  sub ExchangeKeysViaSSL { Line 1078  sub ExchangeKeysViaSSL {
     my ($SSLCACertificate,      my ($SSLCACertificate,
  $SSLCertificate) = lonssl::CertificateFile();   $SSLCertificate) = lonssl::CertificateFile();
     my $SSLKey             = lonssl::KeyFile();      my $SSLKey             = lonssl::KeyFile();
       my $CRLFile;
       unless ($crlchecked{$peerdef}) {
           $CRLFile = lonssl::CRLFile();
           $crlchecked{$peerdef} = 1;
       }
     #  Promote our connection to ssl and read the key from lond.      #  Promote our connection to ssl and read the key from lond.
   
     my $SSLSocket = lonssl::PromoteClientSocket($socket,      my $SSLSocket = lonssl::PromoteClientSocket($socket,
  $SSLCACertificate,   $SSLCACertificate,
  $SSLCertificate,   $SSLCertificate,
  $SSLKey);   $SSLKey,
                                                   $peer,
                                                   $peerdef,
                                                   $CRLFile,
                                                   $loncaparev);
     if(defined $SSLSocket) {      if(defined $SSLSocket) {
  my $key  = <$SSLSocket>;   my $key  = <$SSLSocket>;
  lonssl::Close($SSLSocket);   lonssl::Close($SSLSocket);
Line 1024  sub ExchangeKeysViaSSL { Line 1108  sub ExchangeKeysViaSSL {
     else {      else {
  # Failed!!   # Failed!!
  Debug(3, "Failed to negotiate SSL connection!");   Debug(3, "Failed to negotiate SSL connection!");
  return 0;   return -1;
     }      }
     # should not get here      # should not get here
     return 0;      return 0;
Line 1049  sub ExchangeKeysViaSSL { Line 1133  sub ExchangeKeysViaSSL {
 #  #
 sub CompleteInsecure {  sub CompleteInsecure {
     my $self = shift;      my $self = shift;
     if($InsecureOk) {      if ($self->{InsecureOK}) {
  $self->{AuthenticationMode} = "insecure";   $self->{AuthenticationMode} = "insecure";
  &Debug(8," Transition out of Initialized:insecure");   &Debug(8," Transition out of Initialized:insecure");
  $self->{TransactionRequest} = $self->{TransactionReply};   $self->{TransactionRequest} = $self->{TransactionReply};
Line 1137  sub PeerVersion { Line 1221  sub PeerVersion {
    return $version;     return $version;
 }  }
   
   #
   #  Manipulate the client data field
   #
   sub SetClientData {
       my ($self, $newData) = @_;
       $self->{ClientData} = $newData;
   }
   #
   #  Get the current client data field.
   #
   sub GetClientData {
       my $self = shift;
       return $self->{ClientData};
   }
   
   #
   # Get the HostID of our peer 
   #
   
   sub PeerLoncapaHim {
       my $self = shift;
       return $self->{LoncapaHim};
   }
   
   #
   # Get the Authentication mode
   #
   
   sub GetKeyMode {
       my $self = shift;
       return $self->{AuthenticationMode};
   }
   
 1;  1;
   
 =pod  =pod

Removed from v.1.46  
changed lines
  Added in v.1.62


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