Diff for /loncom/LondConnection.pm between versions 1.49 and 1.57

version 1.49, 2010/11/11 15:01:13 version 1.57, 2018/08/07 17:12:09
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 161  sub new { Line 176  sub new {
     }      }
     &Debug(4,$class."::new( ".$DnsName.",".$Port.",".$lonid.")\n");      &Debug(4,$class."::new( ".$DnsName.",".$Port.",".$lonid.")\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
     #  system and use the hostname for the encryption key       #  system and use the hostname for the encryption key 
Line 176  sub new { Line 206  sub new {
                      Port               => $Port,                       Port               => $Port,
                      State              => "Initialized",                       State              => "Initialized",
      AuthenticationMode => "",       AuthenticationMode => "",
        InsecureOK         => $allowinsecure,
                      TransactionRequest => "",                       TransactionRequest => "",
                      TransactionReply   => "",                       TransactionReply   => "",
                      NextRequest        => "",                       NextRequest        => "",
Line 189  sub new { Line 220  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 232  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 247  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 278  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});
   
  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:$perlvar{'lonVersion'}\n";      $self->{TransactionRequest} = "init:ssl:$perlvar{'lonVersion'}\n";
    } elsif ($self->{InsecureOK}) {
       # Allowed to do insecure:
       $self->{AuthenticationMode} = "insecure";
       $self->{TransactionRequest} = "init::$perlvar{'lonVersion'}\n";
  } else {   } else {
     if($InsecureOk) { # Allowed to do insecure:      # Not allowed to do insecure...
  $self->{AuthenticationMode} = "insecure";      $socket->close;
  $self->{TransactionRequest} = "init::$perlvar{'lonVersion'}\n";      return undef;
     }  
     else { # Not allowed to do insecure...  
  $socket->close;  
  return undef;  
     }  
  }   }
     }      }
   
Line 340  sub Readable { Line 381  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 438  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 501  sub Readable { Line 561  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 622  sub Writable {
  ($errno == POSIX::EAGAIN)         ||   ($errno == POSIX::EAGAIN)         ||
  ($errno == POSIX::EINTR)          ||   ($errno == POSIX::EINTR)          ||
  ($errno ==  0)) {   ($errno ==  0)) {
     $self->{TimeoutRemaining} = $self->{TimeoutValue};   $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 745  sub Shutdown { Line 804  sub Shutdown {
     $socket->shutdown(2);      $socket->shutdown(2);
  }   }
     }      }
       $self->{Timeoutable}   = 0; # Shutdown sockets can't timeout.
 }  }
   
 =pod  =pod
Line 995  sub CreateCipher { Line 1055  sub CreateCipher {
 sub ExchangeKeysViaSSL {  sub ExchangeKeysViaSSL {
     my $self   = shift;      my $self   = shift;
     my $socket = $self->{Socket};      my $socket = $self->{Socket};
       my $peer = $self->{LoncapaHim};
   
     #  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 1003  sub ExchangeKeysViaSSL { Line 1064  sub ExchangeKeysViaSSL {
     my ($SSLCACertificate,      my ($SSLCACertificate,
  $SSLCertificate) = lonssl::CertificateFile();   $SSLCertificate) = lonssl::CertificateFile();
     my $SSLKey             = lonssl::KeyFile();      my $SSLKey             = lonssl::KeyFile();
       my $CRLFile;
       unless ($crlchecked{$peer}) {
           $CRLFile = lonssl::CRLFile();
           $crlchecked{$peer} = 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,
                                                   $CRLFile);
     if(defined $SSLSocket) {      if(defined $SSLSocket) {
  my $key  = <$SSLSocket>;   my $key  = <$SSLSocket>;
  lonssl::Close($SSLSocket);   lonssl::Close($SSLSocket);
Line 1025  sub ExchangeKeysViaSSL { Line 1092  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 1050  sub ExchangeKeysViaSSL { Line 1117  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 1138  sub PeerVersion { Line 1205  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.49  
changed lines
  Added in v.1.57


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