--- loncom/lond 2017/02/07 18:14:13 1.531
+++ loncom/lond 2017/02/28 05:42:06 1.532
@@ -2,7 +2,7 @@
# The LearningOnline Network
# lond "LON Daemon" Server (port "LOND" 5663)
#
-# $Id: lond,v 1.531 2017/02/07 18:14:13 raeburn Exp $
+# $Id: lond,v 1.532 2017/02/28 05:42:06 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -35,6 +35,7 @@ use LONCAPA;
use LONCAPA::Configuration;
use LONCAPA::Lond;
+use Socket;
use IO::Socket;
use IO::File;
#use Apache::File;
@@ -64,7 +65,7 @@ my $DEBUG = 0; # Non zero to ena
my $status='';
my $lastlog='';
-my $VERSION='$Revision: 1.531 $'; #' stupid emacs
+my $VERSION='$Revision: 1.532 $'; #' stupid emacs
my $remoteVERSION;
my $currenthostid="default";
my $currentdomainid;
@@ -75,6 +76,8 @@ my $clientname; # LonCAPA name of clie
my $clientversion; # LonCAPA version running on client.
my $clienthomedom; # LonCAPA domain of homeID for client.
my $clientintdom; # LonCAPA "internet domain" for client.
+my $clientsamedom; # LonCAPA domain same for this host
+ # and client.
my $clientsameinst; # LonCAPA "internet domain" same for
# this host and client.
my $clientremoteok; # Client allowed to host domain's users.
@@ -102,6 +105,9 @@ my %managers; # Ip -> manager names
my %perlvar; # Will have the apache conf defined perl vars.
+my %secureconf; # Will have requirements for security
+ # of lond connections
+
my $dist;
#
@@ -445,8 +451,23 @@ sub InsecureConnection {
my $Socket = shift;
# Don't even start if insecure connections are not allowed.
-
- if(! $perlvar{londAllowInsecure}) { # Insecure connections not allowed.
+ # return 0 if Insecure connections not allowed.
+ #
+ if (ref($secureconf{'connfrom'}) eq 'HASH') {
+ if ($clientsamedom) {
+ if ($secureconf{'connfrom'}{'dom'} eq 'req') {
+ return 0;
+ }
+ } elsif ($clientsameinst) {
+ if ($secureconf{'connfrom'}{'intdom'} eq 'req') {
+ return 0;
+ }
+ } else {
+ if ($secureconf{'connfrom'}{'other'} eq 'req') {
+ return 0;
+ }
+ }
+ } elsif (!$perlvar{londAllowInsecure}) {
return 0;
}
@@ -6803,6 +6824,7 @@ sub UpdateHosts {
# will take care of new and changed hosts as connections come into being.
&Apache::lonnet::reset_hosts_info();
+ my %active;
foreach my $child (keys(%children)) {
my $childip = $children{$child};
@@ -6812,15 +6834,62 @@ sub UpdateHosts {
." $child for ip $childip ");
kill('INT', $child);
} else {
+ $active{$child} = $childip;
logthis(' keeping child for ip '
." $childip (pid=$child) ");
}
}
+
+ my %oldconf = %secureconf;
+ my %connchange;
+ if (lonssl::Read_Connect_Config(\%secureconf,\%perlvar) eq 'ok') {
+ logthis(' Reloaded SSL connection rules ');
+ } else {
+ logthis(' Failed to reload SSL connection rules ');
+ }
+ if ((ref($oldconf{'connfrom'}) eq 'HASH') && (ref($secureconf{'connfrom'}) eq 'HASH')) {
+ foreach my $type ('dom','intdom','other') {
+ if ((($oldconf{'connfrom'}{$type} eq 'no') && ($secureconf{'connfrom'}{$type} eq 'req')) ||
+ (($oldconf{'connfrom'}{$type} eq 'req') && ($secureconf{'connfrom'}{$type} eq 'no'))) {
+ $connchange{$type} = 1;
+ }
+ }
+ }
+ if (keys(%connchange)) {
+ foreach my $child (keys(%active)) {
+ my $childip = $active{$child};
+ if ($childip ne '127.0.0.1') {
+ my $childhostname = gethostbyaddr(Socket::inet_aton($childip),AF_INET);
+ if ($childhostname ne '') {
+ my $childlonhost = &Apache::lonnet::get_server_homeID($childhostname);
+ my ($samedom,$sameinst) = &set_client_info($childlonhost);
+ if ($samedom) {
+ if ($connchange{'dom'}) {
+ logthis(' UpdateHosts killing child '
+ ." $child for ip $childip ");
+ kill('INT', $child);
+ }
+ } elsif ($sameinst) {
+ if ($connchange{'intdom'}) {
+ logthis(' UpdateHosts killing child '
+ ." $child for ip $childip ");
+ kill('INT', $child);
+ }
+ } else {
+ if ($connchange{'other'}) {
+ logthis(' UpdateHosts killing child '
+ ." $child for ip $childip ");
+ kill('INT', $child);
+ }
+ }
+ }
+ }
+ }
+ }
ReloadApache;
&status("Finished reloading hosts.tab");
}
-
sub checkchildren {
&status("Checking on the children (sending signals)");
&initnewstatus();
@@ -7055,6 +7124,10 @@ if ($arch eq 'unknown') {
chomp($arch);
}
+unless (lonssl::Read_Connect_Config(\%secureconf,\%perlvar) eq 'ok') {
+ &logthis('No connectionrules table. Will fallback to loncapa.conf');
+}
+
# --------------------------------------------------------------
# Accept connections. When a connection comes in, it is validated
# and if good, a child process is created to process transactions
@@ -7185,7 +7258,7 @@ sub make_new_child {
$ConnectionType = "manager";
$clientname = $managers{$outsideip};
}
- my $clientok;
+ my ($clientok,$clientinfoset);
if ($clientrec || $ismanager) {
&status("Waiting for init from $clientip $clientname");
@@ -7213,7 +7286,32 @@ sub make_new_child {
# If the connection type is ssl, but I didn't get my
# certificate files yet, then I'll drop back to
# insecure (if allowed).
-
+
+ if ($inittype eq "ssl") {
+ my $context;
+ if ($clientsamedom) {
+ $context = 'dom';
+ if ($secureconf{'connfrom'}{'dom'} eq 'no') {
+ $inittype = "";
+ }
+ } elsif ($clientsameinst) {
+ $context = 'intdom';
+ if ($secureconf{'connfrom'}{'intdom'} eq 'no') {
+ $inittype = "";
+ }
+ } else {
+ $context = 'other';
+ if ($secureconf{'connfrom'}{'other'} eq 'no') {
+ $inittype = "";
+ }
+ }
+ if ($inittype eq '') {
+ &logthis(" Domain config set "
+ ."to no ssl for $clientname (context: $context)"
+ ." -- trying insecure auth");
+ }
+ }
+
if($inittype eq "ssl") {
my ($ca, $cert) = lonssl::CertificateFile;
my $kfile = lonssl::KeyFile;
@@ -7246,7 +7344,7 @@ sub make_new_child {
close $client;
}
} elsif ($inittype eq "ssl") {
- my $key = SSLConnection($client);
+ my $key = SSLConnection($client,$clientname);
if ($key) {
$clientok = 1;
my $cipherkey = pack("H32", $key);
@@ -7261,6 +7359,7 @@ sub make_new_child {
}
} else {
+ $clientinfoset = &set_client_info();
my $ok = InsecureConnection($client);
if($ok) {
$clientok = 1;
@@ -7300,18 +7399,8 @@ sub make_new_child {
# ------------------------------------------------------------ Process requests
my $keep_going = 1;
my $user_input;
- my $clienthost = &Apache::lonnet::hostname($clientname);
- my $clientserverhomeID = &Apache::lonnet::get_server_homeID($clienthost);
- $clienthomedom = &Apache::lonnet::host_domain($clientserverhomeID);
- $clientintdom = &Apache::lonnet::internet_dom($clientserverhomeID);
- $clientsameinst = 0;
- if ($clientintdom ne '') {
- my $internet_names = &Apache::lonnet::get_internet_names($currenthostid);
- if (ref($internet_names) eq 'ARRAY') {
- if (grep(/^\Q$clientintdom\E$/,@{$internet_names})) {
- $clientsameinst = 1;
- }
- }
+ unless ($clientinfoset) {
+ $clientinfoset = &set_client_info();
}
$clientremoteok = 0;
unless ($clientsameinst) {
@@ -7367,6 +7456,60 @@ sub make_new_child {
exit;
}
+
+#
+# Used to determine if a particular client is from the same domain
+# as the current server, or from the same internet domain.
+#
+# Optional input -- the client to check for domain and internet domain.
+# If not specified, defaults to the package variable: $clientname
+#
+# If called in array context will not set package variables, but will
+# instead return an array of two values - (a) true if client is in the
+# same domain as the server, and (b) true if client is in the same internet
+# domain.
+#
+# If called in scalar context, sets package variables for current client:
+#
+# $clienthomedom - LonCAPA domain of homeID for client.
+# $clientsamedom - LonCAPA domain same for this host and client.
+# $clientintdom - LonCAPA "internet domain" for client.
+# $clientsameinst - LonCAPA "internet domain" same for this host & client.
+#
+# returns 1 to indicate package variables have been set for current client.
+#
+
+sub set_client_info {
+ my ($lonhost) = @_;
+ $lonhost ||= $clientname;
+ my $clienthost = &Apache::lonnet::hostname($lonhost);
+ my $clientserverhomeID = &Apache::lonnet::get_server_homeID($clienthost);
+ my $homedom = &Apache::lonnet::host_domain($clientserverhomeID);
+ my $samedom = 0;
+ if ($perlvar{'lonDefDom'} eq $homedom) {
+ $samedom = 1;
+ }
+ my $intdom = &Apache::lonnet::internet_dom($clientserverhomeID);
+ my $sameinst = 0;
+ if ($intdom ne '') {
+ my $internet_names = &Apache::lonnet::get_internet_names($currenthostid);
+ if (ref($internet_names) eq 'ARRAY') {
+ if (grep(/^\Q$intdom\E$/,@{$internet_names})) {
+ $sameinst = 1;
+ }
+ }
+ }
+ if (wantarray) {
+ return ($samedom,$sameinst);
+ } else {
+ $clienthomedom = $homedom;
+ $clientsamedom = $samedom;
+ $clientintdom = $intdom;
+ $clientsameinst = $sameinst;
+ return 1;
+ }
+}
+
#
# Determine if a user is an author for the indicated domain.
#