--- loncom/lond	2017/08/26 03:57:01	1.541
+++ loncom/lond	2018/08/18 22:07:48	1.548
@@ -2,7 +2,7 @@
 # The LearningOnline Network
 # lond "LON Daemon" Server (port "LOND" 5663)
 #
-# $Id: lond,v 1.541 2017/08/26 03:57:01 raeburn Exp $
+# $Id: lond,v 1.548 2018/08/18 22:07:48 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -65,7 +65,7 @@ my $DEBUG = 0;		       # Non zero to ena
 my $status='';
 my $lastlog='';
 
-my $VERSION='$Revision: 1.541 $'; #' stupid emacs
+my $VERSION='$Revision: 1.548 $'; #' stupid emacs
 my $remoteVERSION;
 my $currenthostid="default";
 my $currentdomainid;
@@ -108,6 +108,10 @@ my %perlvar;			# Will have the apache co
 my %secureconf;                 # Will have requirements for security 
                                 # of lond connections
 
+my %crlchecked;                 # Will contain clients for which the client's SSL
+                                # has been checked against the cluster's Certificate
+                                # Revocation List.
+
 my $dist;
 
 #
@@ -420,10 +424,19 @@ sub SSLConnection {
     Debug("Approving promotion -> ssl");
     #  And do so:
 
+    my $CRLFile;
+    unless ($crlchecked{$clientname}) {
+        $CRLFile = lonssl::CRLFile();
+        $crlchecked{$clientname} = 1;
+    }
+
     my $SSLSocket = lonssl::PromoteServerSocket($Socket,
 						$CACertificate,
 						$Certificate,
-						$KeyFile);
+						$KeyFile,
+						$clientname,
+                                                $CRLFile,
+                                                $clientversion);
     if(! ($SSLSocket) ) {	# SSL socket promotion failed.
 	my $err = lonssl::LastError();
 	&logthis("<font color=\"red\"> CRITICAL "
@@ -1882,6 +1895,14 @@ sub ls3_handler {
     my $rights;
     my $ulsout='';
     my $ulsfn;
+
+    my ($crscheck,$toplevel,$currdom,$currnum,$skip);
+    unless ($islocal) {
+        my ($major,$minor) = split(/\./,$clientversion);
+        if (($major < 2) || ($major == 2 && $minor < 12)) {
+            $crscheck = 1;
+        }
+    }
     if (-e $ulsdir) {
         if(-d $ulsdir) {
             unless (($getpropath) || ($getuserdir) ||
@@ -1891,8 +1912,26 @@ sub ls3_handler {
                 &Failure($client,"refused\n",$userinput);
                 return 1;
             }
-            if (opendir(LSDIR,$ulsdir)) {
+            if (($crscheck) &&
+                ($ulsdir =~ m{^/home/httpd/html/res/($LONCAPA::match_domain)(/?$|/$LONCAPA::match_courseid)})) {
+                ($currdom,my $posscnum) = ($1,$2);
+                if (($posscnum eq '') || ($posscnum eq '/')) {
+                    $toplevel = 1;
+                } else {
+                    $posscnum =~ s{^/+}{};
+                    if (&LONCAPA::Lond::is_course($currdom,$posscnum)) {
+                        $skip = 1;
+                    }
+                }
+            }
+            if ((!$skip) && (opendir(LSDIR,$ulsdir))) {
                 while ($ulsfn=readdir(LSDIR)) {
+                    if (($crscheck) && ($toplevel) && ($currdom ne '') &&
+                        ($ulsfn =~ /^$LONCAPA::match_courseid$/) && (-d "$ulsdir/$ulsfn")) {
+                        if (&LONCAPA::Lond::is_course($currdom,$ulsfn)) {
+                            next;
+                        }
+                    }
                     undef($obs);
                     undef($rights);
                     my @ulsstats=stat($ulsdir.'/'.$ulsfn);
@@ -2070,8 +2109,8 @@ sub server_distarch_handler {
 sub server_certs_handler {
     my ($cmd,$tail,$client) = @_;
     my $userinput = "$cmd:$tail";
-    my $result;
-    my $result = &LONCAPA::Lond::server_certs(\%perlvar);
+    my $hostname = &Apache::lonnet::hostname($perlvar{'lonHostID'});
+    my $result = &LONCAPA::Lond::server_certs(\%perlvar,$perlvar{'lonHostID'},$hostname);
     &Reply($client,\$result,$userinput);
     return;
 }
@@ -5746,9 +5785,10 @@ sub validate_course_section_handler {
 # Formal Parameters:
 #    $cmd     - The command request that got us dispatched.
 #    $tail    - The tail of the command.   In this case this is a colon separated
-#               set of words that will be split into:
+#               set of values that will be split into:
 #               $inst_class  - Institutional code for the specific class section   
-#               $courseowner - The escaped username:domain of the course owner 
+#               $ownerlist   - An escaped comma-separated list of username:domain 
+#                              of the course owner, and co-owner(s).
 #               $cdom        - The domain of the course from the institution's
 #                              point of view.
 #    $client  - The socket open on the client.
@@ -5773,6 +5813,56 @@ sub validate_class_access_handler {
 &register_handler("autovalidateclass_sec", \&validate_class_access_handler, 0, 1, 0);
 
 #
+#   Validate course owner or co-owners(s) access to enrollment data for all sections
+#   and crosslistings for a particular course.
+#
+#
+# Formal Parameters:
+#    $cmd     - The command request that got us dispatched.
+#    $tail    - The tail of the command.   In this case this is a colon separated
+#               set of values that will be split into:
+#               $ownerlist   - An escaped comma-separated list of username:domain
+#                              of the course owner, and co-owner(s).
+#               $cdom        - The domain of the course from the institution's
+#                              point of view.
+#               $classes     - Frozen hash of institutional course sections and
+#                              crosslistings.
+#    $client  - The socket open on the client.
+# Returns:
+#    1 - continue processing.
+#
+
+sub validate_classes_handler {
+    my ($cmd, $tail, $client) = @_;
+    my $userinput = "$cmd:$tail";
+    my ($ownerlist,$cdom,$classes) = split(/:/, $tail);
+    my $classesref = &Apache::lonnet::thaw_unescape($classes);
+    my $owners = &unescape($ownerlist);
+    my $result;
+    eval {
+        local($SIG{__DIE__})='DEFAULT';
+        my %validations;
+        my $response = &localenroll::check_instclasses($owners,$cdom,$classesref,
+                                                       \%validations);
+        if ($response eq 'ok') {
+            foreach my $key (keys(%validations)) {
+                $result .= &escape($key).'='.&Apache::lonnet::freeze_escape($validations{$key}).'&';
+            }
+            $result =~ s/\&$//;
+        } else {
+            $result = 'error';
+        }
+    };
+    if (!$@) {
+        &Reply($client, \$result, $userinput);
+    } else {
+        &Failure($client,"unknown_cmd\n",$userinput);
+    }
+    return 1;
+}
+&register_handler("autovalidateinstclasses", \&validate_classes_handler, 0, 1, 0);
+
+#
 #   Create a password for a new LON-CAPA user added by auto-enrollment.
 #   Only used for case where authentication method for new user is localauth
 #
@@ -6941,10 +7031,10 @@ sub UpdateHosts {
 
     my %oldconf = %secureconf;
     my %connchange;
-    if (lonssl::Read_Connect_Config(\%secureconf,\%perlvar) eq 'ok') {
-        logthis('<font color="blue"> Reloaded SSL connection rules </font>');
+    if (lonssl::Read_Connect_Config(\%secureconf,\%crlchecked,\%perlvar) eq 'ok') {
+        logthis('<font color="blue"> Reloaded SSL connection rules and cleared CRL checking history </font>');
     } else {
-        logthis('<font color="yellow"> Failed to reload SSL connection rules </font>');
+        logthis('<font color="yellow"> Failed to reload SSL connection rules and clear CRL checking history </font>');
     }
     if ((ref($oldconf{'connfrom'}) eq 'HASH') && (ref($secureconf{'connfrom'}) eq 'HASH')) {
         foreach my $type ('dom','intdom','other') {
@@ -7223,7 +7313,7 @@ if ($arch eq 'unknown') {
     chomp($arch);
 }
 
-unless (lonssl::Read_Connect_Config(\%secureconf,\%perlvar) eq 'ok') {
+unless (lonssl::Read_Connect_Config(\%secureconf,\%crlchecked,\%perlvar) eq 'ok') {
     &logthis('<font color="blue">No connectionrules table. Will fallback to loncapa.conf</font>');
 }
 
@@ -8318,6 +8408,14 @@ sub make_passwd_file {
 		$result = "pass_file_failed_error";
 	    }
 	}
+    } elsif ($umode eq 'lti') {
+        my $pf = IO::File->new(">$passfilename");
+        if($pf) {
+            print $pf "lti:\n";
+            &update_passwd_history($uname,$udom,$umode,$action);
+        } else {
+            $result = "pass_file_failed_error";
+        }
     } else {
 	$result="auth_mode_error";
     }