--- loncom/loncron	2017/02/28 05:42:06	1.104
+++ loncom/loncron	2018/10/29 02:57:30	1.112
@@ -2,7 +2,7 @@
 
 # Housekeeping program, started by cron, loncontrol and loncron.pl
 #
-# $Id: loncron,v 1.104 2017/02/28 05:42:06 raeburn Exp $
+# $Id: loncron,v 1.112 2018/10/29 02:57:30 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -113,17 +113,20 @@ sub checkon_daemon {
     my $result;
     &log($fh,'<hr /><a name="'.$daemon.'" /><h2>'.$daemon.'</h2><h3>Log</h3><p style="white-space: pre;"><tt>');
     printf("%-15s ",$daemon);
-    if (-e "$perlvar{'lonDaemons'}/logs/$daemon.log"){
-	open (DFH,"tail -n25 $perlvar{'lonDaemons'}/logs/$daemon.log|");
-	while (my $line=<DFH>) { 
-	    &log($fh,"$line");
-	    if ($line=~/INFO/) { $notices++; }
-	    if ($line=~/WARNING/) { $notices++; }
-	    if ($line=~/CRITICAL/) { $warnings++; }
-	};
-	close (DFH);
+    if ($fh) {
+        if (-e "$perlvar{'lonDaemons'}/logs/$daemon.log"){
+	    if (open(DFH,"tail -n25 $perlvar{'lonDaemons'}/logs/$daemon.log|")) {
+	        while (my $line=<DFH>) { 
+	            &log($fh,"$line");
+	            if ($line=~/INFO/) { $notices++; }
+	            if ($line=~/WARNING/) { $notices++; }
+	            if ($line=~/CRITICAL/) { $warnings++; }
+	        }
+	        close (DFH);
+            }
+        }
+        &log($fh,"</tt></p>");
     }
-    &log($fh,"</tt></p>");
     
     my $pidfile="$perlvar{'lonDaemons'}/logs/$daemon.pid";
     
@@ -165,8 +168,11 @@ sub checkon_daemon {
 	&log($fh,unlink($pidfile).' - '.
 	    `killall -9 $kadaemon 2>&1`.
 	    '</font><br />');
+        if ($kadaemon eq 'loncnew') {
+            &clean_lonc_childpids();
+        }
 	&log($fh,"<h3>$daemon not running, trying to start</h3>");
-	
+
 	if (&start_daemon($fh,$daemon,$pidfile,$args)) {
 	    &log($fh,"<h3>$daemon at pid $daemonpid responding</h3>");
 	    $simplestatus{$daemon}='restarted';
@@ -191,17 +197,19 @@ sub checkon_daemon {
 		&log($fh,"<p>Unable to start $daemon</p>");
 	    }
 	}
-
-	if (-e "$perlvar{'lonDaemons'}/logs/$daemon.log"){
-	    &log($fh,"<p><pre>");
-	    open (DFH,"tail -n100 $perlvar{'lonDaemons'}/logs/$daemon.log|");
-	    while (my $line=<DFH>) { 
-		&log($fh,"$line");
-		if ($line=~/WARNING/) { $notices++; }
-		if ($line=~/CRITICAL/) { $notices++; }
-	    };
-	    close (DFH);
-	    &log($fh,"</pre></p>");
+        if ($fh) {
+	    if (-e "$perlvar{'lonDaemons'}/logs/$daemon.log"){
+	        &log($fh,"<p><pre>");
+	        if (open(DFH,"tail -n100 $perlvar{'lonDaemons'}/logs/$daemon.log|")) {
+	            while (my $line=<DFH>) { 
+		        &log($fh,"$line");
+		        if ($line=~/WARNING/) { $notices++; }
+		        if ($line=~/CRITICAL/) { $notices++; }
+	            }
+	            close (DFH);
+                }
+	        &log($fh,"</pre></p>");
+            }
 	}
     }
     
@@ -646,9 +654,15 @@ sub check_delayed_msg {
 
     my $unsend=0;
 
+    my %hostname = &Apache::lonnet::all_hostnames();
+    my $numhosts = scalar(keys(%hostname));
+
     my $dfh=IO::File->new("$perlvar{'lonDaemons'}/logs/lonnet.perm.log");
     while (my $line=<$dfh>) {
 	my ($time,$sdf,$dserv,$dcmd)=split(/:/,$line);
+        if ($numhosts) {
+            next unless ($hostname{$dserv});
+        }
 	if ($sdf eq 'F') { 
 	    my $local=localtime($time);
 	    &log($fh,"<b>Failed: $time, $dserv, $dcmd</b><br />");
@@ -675,8 +689,6 @@ sub check_delayed_msg {
     }
     &log($fh,"</pre>\n");
     close (DFH);
-    my %hostname = &Apache::lonnet::all_hostnames();
-    my $numhosts = scalar(keys(%hostname));
 # pong to all servers that have delayed messages
 # this will trigger a reverse connection, which should flush the buffers
     foreach my $tryserver (sort(keys(%servers))) {
@@ -817,8 +829,39 @@ sub write_checksums {
     return;
 }
 
+sub clean_nosslverify {
+    my ($fh) = @_;
+    my %unlinked; 
+    if (-d "$perlvar{'lonSockDir'}/nosslverify") {
+        if (opendir(my $dh,"$perlvar{'lonSockDir'}/nosslverify")) {
+            while (my $fname=readdir($dh)) {
+                next if ($fname =~ /^\.+$/);
+                if (unlink("/home/httpd/sockets/nosslverify/$fname")) {
+                    &log($fh,"Unlinking $fname<br />");
+                    $unlinked{$fname} = 1;
+                }
+            }
+            closedir($dh);
+        }
+    }
+    &log($fh,"<p>Removed ".scalar(keys(%unlinked))." nosslverify clients</p>");
+    return %unlinked;
+}
+sub clean_lonc_childpids {
+    my $childpiddir = "$perlvar{'lonDocRoot'}/lon-status/loncchld";
+    if (-d $childpiddir) {
+        if (opendir(my $dh,$childpiddir)) {
+            while (my $fname=readdir($dh)) {
+                next if ($fname =~ /^\.+$/);
+                unlink("$childpiddir/$fname");
+            }
+            closedir($dh);
+        }
+    }
+}
+
 sub write_connection_config {
-    my ($isprimary,$domconf,$url,%connectssl);
+    my ($isprimary,$domconf,$url,%connectssl,%changes);
     my $primaryLibServer = &Apache::lonnet::domain($perlvar{'lonDefDomain'},'primary');
     if ($primaryLibServer eq $perlvar{'lonHostID'}) {
         $isprimary = 1;
@@ -845,10 +888,30 @@ sub write_connection_config {
             }
         }
         if (keys(%connectssl)) {
-            if (open(my $fh,">$perlvar{'lonTabDir'}/connectionrules.tab")) {
+            my %currconf; 
+            if (open(my $fh,'<',"$perlvar{'lonTabDir'}/connectionrules.tab")) {
+                while (my $line = <$fh>) {
+                    chomp($line);
+                    my ($name,$value) = split(/=/,$line);
+                    if ($value =~ /^(?:no|yes|req)$/) {
+                        if ($name =~ /^conn(to|from)_(dom|intdom|other)$/) {
+                            $currconf{$name} = $value;
+                        }
+                    }
+                }
+                close($fh);
+            }
+            if (open(my $fh,'>',"$perlvar{'lonTabDir'}/connectionrules.tab")) {
                 my $count = 0;
                 foreach my $key (sort(keys(%connectssl))) { 
                     print $fh "$key=$connectssl{$key}\n";
+                    if (exists($currconf{$key})) {
+                        unless ($currconf{$key} eq $connectssl{$key}) {
+                            $changes{$key} = 1;
+                        }
+                    } else {
+                        $changes{$key} = 1;
+                    }
                     $count ++;
                 }
                 close($fh);
@@ -860,6 +923,7 @@ sub write_connection_config {
     } else {
         print "Retrieval of SSL options for lonc/lond skipped - no configuration data available for domain.\n";
     }
+    return %changes;
 }
 
 sub get_domain_config {
@@ -913,9 +977,21 @@ sub write_hosttypes {
     my %hostdom = &Apache::lonnet::all_host_domain();
     my $dom = $hostdom{$perlvar{'lonHostID'}};
     my $internetdom = $intdom{$perlvar{'lonHostID'}};
+    my %changes;
     if (($dom ne '') && ($internetdom ne '')) {
         if (keys(%hostdom)) {
-            if (open(my $fh,">$perlvar{'lonTabDir'}/hosttypes.tab")) {
+            my %currhosttypes;
+            if (open(my $fh,'<',"$perlvar{'lonTabDir'}/hosttypes.tab")) {
+                while (my $line = <$fh>) {
+                    chomp($line);
+                    my ($name,$value) = split(/:/,$line);
+                    if (($name ne '') && ($value =~ /^(dom|intdom|other)$/)) {
+                        $currhosttypes{$name} = $value;
+                    }
+                }
+                close($fh);
+            }
+            if (open(my $fh,'>',"$perlvar{'lonTabDir'}/hosttypes.tab")) {
                 my $count = 0;
                 foreach my $lonid (sort(keys(%hostdom))) {
                     my $type = 'other';
@@ -925,6 +1001,13 @@ sub write_hosttypes {
                         $type = 'intdom';
                     }
                     print $fh "$lonid:$type\n";
+                    if (exists($currhosttypes{$lonid})) {
+                        if ($type ne $currhosttypes{$lonid}) {
+                            $changes{$lonid} = 1;
+                        }
+                    } else {
+                        $changes{$lonid} = 1;
+                    }
                     $count ++;
                 }
                 close($fh);
@@ -936,6 +1019,72 @@ sub write_hosttypes {
     } else {
         print "Writing of host types skipped - could not determine this host's LON-CAPA domain or 'internet' domain.\n";
     }
+    return %changes;
+}
+
+sub update_revocation_list {
+    my ($result,$changed) = &Apache::lonnet::fetch_crl_pemfile();
+    if ($result eq 'ok') {
+        print "Certificate Revocation List (from CA) updated.\n";
+    } else {
+        print "Certificate Revocation List from (CA) not updated.\n";
+    }
+    return $changed;
+}
+
+sub reset_nosslverify_pids {
+    my ($fh,%sslrem) = @_;
+    &checkon_daemon($fh,'lond',40000,'USR2');
+    my $loncpidfile="$perlvar{'lonDaemons'}/logs/lonc.pid";
+    my $loncppid;
+    if ((-e $loncpidfile) && (open(my $pfh,'<',$loncpidfile))) {
+        $loncppid=<$pfh>;
+        chomp($loncppid);
+        close($pfh);
+        if ($loncppid =~ /^\d+$/) {
+            my %pids_by_host;
+            my $docdir = $perlvar{'lonDocRoot'};
+            if (-d "$docdir/lon-status/loncchld") {
+                if (opendir(my $dh,"$docdir/lon-status/loncchld")) {
+                    while (my $file = readdir($dh)) {
+                        next if ($file =~ /^\./);
+                        if (open(my $fh,'<',"$docdir/lon-status/loncchld/$file")) {
+                            my $record = <$fh>;
+                            chomp($record);
+                            close($fh);
+                            my ($remotehost,$authmode) = split(/:/,$record);
+                            $pids_by_host{$remotehost}{$authmode}{$file} = 1;
+                        }
+                    }
+                    closedir($dh);
+                    if (keys(%pids_by_host)) {
+                        foreach my $host (keys(%pids_by_host)) {
+                            if ($sslrem{$host}) {
+                                if (ref($pids_by_host{$host}) eq 'HASH') {
+                                    if (ref($pids_by_host{$host}{'insecure'}) eq 'HASH') {
+                                        if (keys(%{$pids_by_host{$host}{'insecure'}})) {
+                                            foreach my $pid (keys(%{$pids_by_host{$host}{'insecure'}})) {
+                                                if (open(PIPE,"ps -o ppid= -p $pid |")) {
+                                                    my $ppid = <PIPE>;
+                                                    chomp($ppid);
+                                                    close(PIPE);
+                                                    $ppid =~ s/(^\s+|\s+$)//g;
+                                                    if (($ppid == $loncppid) && (kill 0 => $pid)) {
+                                                        kill QUIT => $pid;
+                                                    }
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return;
 }
 
 sub send_mail {
@@ -1027,8 +1176,8 @@ sub main () {
 	chop $hostname;
 	$hostname=~s/[^\w\.]//g; # make sure is safe to pass through shell
 	my $subj="LON: Unconfigured machine $hostname";
-	system("echo 'Unconfigured machine $hostname.' |\
- mailto $emailto -s '$subj' > /dev/null");
+	system("echo 'Unconfigured machine $hostname.' |".
+               " mail -s '$subj' $emailto > /dev/null");
 	exit 1;
     }
 
@@ -1038,8 +1187,8 @@ sub main () {
 	print("User ID mismatch. This program must be run as user 'www'.\n");
 	my $emailto="$perlvar{'lonAdmEMail'},$perlvar{'lonSysEMail'}";
 	my $subj="LON: $perlvar{'lonHostID'} User ID mismatch";
-	system("echo 'User ID mismatch. loncron must be run as user www.' |\
- mailto $emailto -s '$subj' > /dev/null");
+	system("echo 'User ID mismatch. loncron must be run as user www.' |".
+               " mail -s '$subj' $emailto > /dev/null");
 	exit 1;
     }
 
@@ -1113,8 +1262,10 @@ sub main () {
         &checkon_daemon($fh,'lonr',40000);
     }
     if ($justreload) {
+        &clean_nosslverify($fh);
         &write_connection_config();
         &write_hosttypes();
+        &update_revocation_list(); 
 	&checkon_daemon($fh,'lond',40000,'USR2');
 	&checkon_daemon($fh,'lonc',40000,'USR2');
     }
@@ -1123,13 +1274,20 @@ sub main () {
     }
     if (!$justcheckdaemons && !$justcheckconnections && !$justreload) {
 	&check_delayed_msg($fh);
-	&finish_logging($fh);
 	&log_simplestatus();
         &write_loncaparevs();
         &write_serverhomeIDs();
 	&write_checksums();
-        &write_connection_config();
-        &write_hosttypes();
+        my %sslrem = &clean_nosslverify($fh);
+        my %conchgs = &write_connection_config();
+        my %hosttypechgs = &write_hosttypes();
+        my $hadcrlchg = &update_revocation_list();
+        if ((keys(%conchgs) > 0) || (keys(%hosttypechgs) > 0) ||
+            $hadcrlchg || (keys(%sslrem) > 0)) {
+            &checkon_daemon($fh,'lond',40000,'USR2');
+            &reset_nosslverify_pids($fh,%sslrem);
+        }
+        &finish_logging($fh);
 	if ($totalcount>200 && !$noemail) { &send_mail(); }
     }
 }