Diff for /doc/install/linux/install.pl between versions 1.46 and 1.47

version 1.46, 2018/07/11 01:58:41 version 1.47, 2018/07/17 00:19:51
Line 26 Line 26
 use strict;  use strict;
 use File::Copy;  use File::Copy;
 use Term::ReadKey;  use Term::ReadKey;
   use Socket;
 use Sys::Hostname::FQDN();  use Sys::Hostname::FQDN();
 use DBI;  use DBI;
 use Cwd();  use Cwd();
Line 281  sub get_distro { Line 282  sub get_distro {
     return ($distro,$packagecmd,$updatecmd,$installnow);      return ($distro,$packagecmd,$updatecmd,$installnow);
 }  }
   
   #
   # get_hostname() prompts the user to provide the server's hostname.
   #
   # If invalid input is provided, the routine is called recursively 
   # until, a valid hostname is provided.
   # 
   
 sub get_hostname {  sub get_hostname {
     my $hostname;      my $hostname;
     print &mt('Enter the hostname of this server, e.g., loncapa.somewhere.edu'."\n");      print &mt('Enter the hostname of this server, e.g., loncapa.somewhere.edu'."\n");
Line 301  sub get_hostname { Line 309  sub get_hostname {
     return $hostname;      return $hostname;
 }  }
   
   #
   # get_hostname() prompts the user to provide the server's IPv4 IP address
   #
   # If invalid input is provided, the routine is called recursively 
   # until, a valid IPv4 address is provided.
   #
   
   sub get_hostip {
       my $hostip;
       print &mt('Enter the IP address of this server, e.g., 192.168.10.24'."\n");
       my $choice = <STDIN>;
       chomp($choice);
       $choice =~ s/(^\s+|\s+$)//g;
       my $badformat = 1;
       if ($choice eq '') {
           print &mt("IP address you entered was either blank or contained only white space.\n"); 
       } else {
           if ($choice =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/) {
               if (($1<=255) && ($2<=255) && ($3<=255) && ($4<=255)) {
                   $badformat = 0; 
               }
           }
           if ($badformat) { 
                print &mt('Host IP you entered was invalid -- a host IP has the format d.d.d.d where each d is an integer between 0 and 255')."\n";
           } else {
               $hostip = $choice;
           }
       }
       while ($hostip eq '') {
           $hostip = &get_hostip();
       }
       print "\n";
       return $hostip;
   }
   
 sub check_prerequisites {  sub check_prerequisites {
     my ($packagecmd,$distro) = @_;      my ($packagecmd,$distro) = @_;
     my $gotprereqs;      my $gotprereqs;
Line 411  sub check_required { Line 454  sub check_required {
     }      }
     my ($mysqlon,$mysqlsetup,$mysqlrestart,$dbh,$has_pass,$has_lcdb,%recommended,      my ($mysqlon,$mysqlsetup,$mysqlrestart,$dbh,$has_pass,$has_lcdb,%recommended,
         $downloadstatus,$filetouse,$production,$testing,$apachefw,$tostop,          $downloadstatus,$filetouse,$production,$testing,$apachefw,$tostop,
         $uses_systemctl,$hostname);          $uses_systemctl,$hostname,$hostip);
     my $wwwuid = &uid_of_www();      my $wwwuid = &uid_of_www();
     my $wwwgid = getgrnam('www');      my $wwwgid = getgrnam('www');
     if (($wwwuid eq '') || ($wwwgid eq '')) {      if (($wwwuid eq '') || ($wwwgid eq '')) {
Line 420  sub check_required { Line 463  sub check_required {
     unless( -e "/usr/local/sbin/pwauth") {      unless( -e "/usr/local/sbin/pwauth") {
         $recommended{'pwauth'} = 1;          $recommended{'pwauth'} = 1;
     }      }
     my $hostname = Sys::Hostname::FQDN::fqdn();      $hostname = Sys::Hostname::FQDN::fqdn();
     if ($hostname eq '') {      if ($hostname eq '') {
         $hostname =&get_hostname();          $hostname =&get_hostname();
     } else {      } else {
Line 429  sub check_required { Line 472  sub check_required {
             $hostname =&get_hostname();              $hostname =&get_hostname();
         }          }
     }      }
     print_and_log(&mt('Hostname is [_1]',$hostname)."\n");      $hostname = Sys::Hostname::FQDN::fqdn();
       $hostip = Socket::inet_ntoa(scalar(gethostbyname($hostname)) || 'localhost');
       if ($hostip eq '') {
           $hostip=&get_hostip();
       } else {
           print &mt("Host IP address detected: $hostip. Is that correct? ~[Y/n~]");
           if (!&get_user_selection(1)) {
               $hostip=&get_hostip();
           }
       }
       print_and_log("\n".&mt('Hostname is [_1] and IP address is [_2]',$hostname,$hostip)."\n");
     $mysqlon = &check_mysql_running($distro);      $mysqlon = &check_mysql_running($distro);
     if ($mysqlon) {      if ($mysqlon) {
         my $mysql_has_wwwuser = &check_mysql_wwwuser();          my $mysql_has_wwwuser = &check_mysql_wwwuser();
Line 458  sub check_required { Line 511  sub check_required {
             }              }
         }          }
     }      }
       my ($sslhostsfilesref,$has_std,$has_int,$rewritenum,$nochgstd,$nochgint);
     ($recommended{'firewall'},$apachefw) = &chkfirewall($distro);      ($recommended{'firewall'},$apachefw) = &chkfirewall($distro);
     ($recommended{'runlevels'},$tostop,$uses_systemctl) = &chkconfig($distro,$instdir);      ($recommended{'runlevels'},$tostop,$uses_systemctl) = &chkconfig($distro,$instdir);
     $recommended{'apache'} = &chkapache($distro,$instdir);      $recommended{'apache'} = &chkapache($distro,$instdir);
     $recommended{'apachessl'} = &chkapachessl($distro,$instdir,$hostname);      ($recommended{'apachessl'},$sslhostsfilesref,$has_std,$has_int,$rewritenum,
        $nochgstd,$nochgint) = &chkapachessl($distro,$instdir,$hostname,$hostip);
     $recommended{'stopsrvcs'} = &chksrvcs($distro,$tostop);      $recommended{'stopsrvcs'} = &chksrvcs($distro,$tostop);
     ($recommended{'download'},$downloadstatus,$filetouse,$production,$testing)       ($recommended{'download'},$downloadstatus,$filetouse,$production,$testing) 
         = &need_download();          = &need_download();
     return ($distro,$gotprereqs,$localecmd,$packagecmd,$updatecmd,$installnow,      return ($distro,$gotprereqs,$localecmd,$packagecmd,$updatecmd,$installnow,
             $mysqlrestart,\%recommended,$dbh,$has_pass,$has_lcdb,$downloadstatus,              $mysqlrestart,\%recommended,$dbh,$has_pass,$has_lcdb,$downloadstatus,
             $filetouse,$production,$testing,$apachefw,$uses_systemctl,$hostname);              $filetouse,$production,$testing,$apachefw,$uses_systemctl,$hostname,
               $hostip,$sslhostsfilesref,$has_std,$has_int,$rewritenum,$nochgstd,
               $nochgint);
 }  }
   
 sub check_mysql_running {  sub check_mysql_running {
Line 882  sub chkapache { Line 939  sub chkapache {
     return $fixapache;      return $fixapache;
 }  }
   
   #
   # chkapachessl() determines whether a server's Apache SSL configuration
   # needs updating to support LON-CAPA.
   #
   # LON-CAPA uses VirtualHosts for port 443, and requires that they are 
   # defined in one Apache configuration file containing two VirtualHost
   # blocks, in order:
   #
   # (1) a block with no ServerName, or with ServerName set to the
   #     server's hostname. This block should contain:
   #
   # <IfModule mod_rewrite.c>
   # LON-CAPA rewrite rules defined in sslrewrite.conf
   # </IfModule>
   #
   # (2) a block with ServerName set to internal-$hostname
   #     (where $hostname is server's hostname).
   #    This block should contain the config and rewrite rules
   #    found in loncapassl.conf.
   #
   # chkapachessl() retrieves the names of .conf files in
   # the directory appropriate for the particular Linux distro,
   # and then checks to see which .conf file is the best candidate as
   # the single file containing VirtualHosts definitions and 
   # <IfModule mod_rewrite.c> </IfModule> rewrite blocks.
   #
   # The best candidate is the one containing a block:
   # <VirtualHost ????? :443> 
   # (where ????? might be _default_ or * or an IP address)
   # <IfModule mod_rewrite.c>
   # </IfModule>
   # </VirtualHost>
   # with the fewest differences between the contents of the 
   # IfModule block and the expected contents (from sslrewrite.conf)
   #
   # If there are no files with rewrite blocks, then a candidate file 
   # is chosen from the .conf files containing VirtualHosts definitions.
   #
   # If the user includes "Configure SSL for Apache web server" as
   # one of the actions to take to prepare the server for LON-CAPA
   # installation, then the output from &chkapachessl() will be
   # used to determined which file will contain VirtualHost configs.  
   #
   # If there are no files containing VirtualHosts definitions, then
   # <VirtualHost *:443> </VirtualHost> blocks will be appended to
   # the standard Apache SSL config for the particular distro:
   # ssl.conf for RHEL/CentOS/Scientific/Fedora, vhost-ssl.conf
   # for SuSE/SLES, and default-ssl.conf for Ubuntu.
   #
   # Once a file is selected, the contents of sslrewrite.conf and 
   # loncapassl.conf are compared with appropriate blocks in the file
   # and the user will be prompted to agree to insertion of missing
   # lines and/or deletion of surplus lines.
   #
   
 sub chkapachessl {  sub chkapachessl {
     my ($distro,$instdir,$hostname) = @_;      my ($distro,$instdir,$hostname,$hostip) = @_;
     my $fixapachessl = 1;      my $fixapachessl = 1;
     my $stdconf = "$instdir/loncapassl.conf";      my $sslintconf = "$instdir/loncapassl.conf";
     if (!-e $stdconf) {      my $sslrewriteconf = "$instdir/sslrewrite.conf";
       my (%sslfiles,%rewrites,%vhostonly,$has_std,$has_int,$rewritenum,$nochgint,$nochgstd);
       $nochgstd = 0;
       $nochgint = 0; 
       if (!-e $sslintconf) {
           $fixapachessl = 0;
           print &mt('Warning: LON-CAPA SSL Apache configuration file [_1] needed for installation check.',$sslintconf)."\n";
       } elsif (!-e $sslrewriteconf) {
         $fixapachessl = 0;          $fixapachessl = 0;
         print &mt('Warning: No LON-CAPA SSL Apache configuration file found for installation check.')."\n";          print &mt('Warning: LON-CAPA SSL Apache configuration file [_1] needed for installation check is missing.',$sslrewriteconf)."\n";
     } else {      } else {
         my $sslfile;           my $ssldir;
         if ($distro =~ /^(debian|ubuntu)(\d+)$/) {          if ($distro =~ /^(debian|ubuntu)(\d+)$/) {
             $sslfile = '/etc/apache2/sites-available/loncapassl.conf';              $ssldir = '/etc/apache2/sites-available';
         } elsif ($distro =~ /(suse|sles)/) {          } elsif ($distro =~ /(suse|sles)/) {
             $sslfile = '/etc/apache2/vhosts.d/loncapassl.conf';              $ssldir = '/etc/apache2/vhosts.d';
         } else {          } else {
             $sslfile = '/etc/httpd/conf.d/loncapassl.conf';              $ssldir = '/etc/httpd/conf.d';
         }          }
         if ((-e $sslfile) && (-e $stdconf))  {          my @rewritessl = ();
             if (open(PIPE, "diff -y -bi --suppress-common-lines $stdconf $sslfile |")) {          if (open(my $fh,'<',$sslrewriteconf)) {
                 my $diffres = <PIPE>;              my $skipnext = 0;
                 close(PIPE);              while (<$fh>) {
                 chomp($diffres);                  chomp();
                 if ($diffres =~ /^\QServerName internal-{[[[[Hostname]]]]}\E\s+\|\s+\QServerName internal-\E$hostname$/) {                  s/(^\s+|\s+$)//g;
                     $fixapachessl = 0;                  next if ($_ eq '');
                   next if ($_ eq '<IfModule mod_rewrite.c>');
                   next if ($_ eq '</IfModule>');
                   if ($_ eq 'RewriteCond %{REMOTE_ADDR} {[[[[HostIP]]]]}') {
                       if (($hostip ne '') && ($hostip ne '127.0.0.1')) {
                           push(@rewritessl,'RewriteCond %{REMOTE_ADDR} '.$hostip);
                           next;
                       } else {
                           $skipnext = 1;
                       }
                   } elsif (($_ eq 'RewriteRule (.*) - [L]') && ($skipnext)) {
                       $skipnext = 0;
                       next;
                   }
                   push(@rewritessl,$_);
               }
           }
           my @intssl = ();
           if (open(my $fh,'<',$sslintconf)) {
               while(<$fh>) {
                   chomp();
                   s/(^\s+|\s+$)//g;
                   next if ($_ eq '');
                   if ($_ eq 'ServerName internal-{[[[[Hostname]]]]}') {
                       if ($hostname ne '') {
                           push(@intssl,'ServerName internal-'.$hostname);
                           next;
                       }
                   }
                   next if ($_ eq '<VirtualHost *:443>');
                   next if ($_ eq '</VirtualHost>');
                   push(@intssl,$_);
               }
           }
           if (-d $ssldir) {
               my @actualint = ();
               if (opendir(my $dir,$ssldir)) {
                   my @sslconf_files;
                   foreach my $file (grep(!/^\.+/,readdir($dir))) {
                       next if (($distro =~ /(suse|sles)/) && ($file =~ /\.template$/));
                       next if ($file =~ /\.rpmnew$/);
                       if (open(my $fh,'<',"$ssldir/$file")) {
                           while (<$fh>) {
                               if (/^\s*<VirtualHost\s+[^:]*\:443>\s*$/) {
                                   push(@sslconf_files,$file);
                                   last;
                               }
                           }
                           close($fh);
                       }
                   }
                   closedir($dir);
                   if (@sslconf_files) {
                       foreach my $file (@sslconf_files) {
                           if (open(my $fh,'<',"$ssldir/$file")) {
                               my ($virtualhost,$rewrite,$num) = (0,0,0);
                               my ($currname,$has_rewrite);
                               while (<$fh>) {
                                   chomp();
                                   next if (/^\s*$/);
                                   if ($virtualhost) {
                                       if (/^\s*<\/VirtualHost>/) {
                                           if ($currname !~ /^\Qinternal-$hostname\E/) {
                                               if ($has_rewrite) {
                                                   delete($vhostonly{$file});
                                               } else {
                                                   $vhostonly{$file} = 1;
                                               }
                                           }
                                           $sslfiles{$currname}{$file} = 1;
                                           $virtualhost = 0;
                                           $currname = '';
                                           $has_rewrite = '';
                                           next;
                                       } elsif (/^\s*ServerName\s+([^\s]+)\s*$/) {
                                           $currname = $1;
                                       }
                                       if ($currname =~ /^\Qinternal-$hostname\E/) {
                                           s/(^\s+|\s+$)//g;
                                           push(@actualint,$_);
                                           $has_int = $file;
                                       } else {
                                           if ($rewrite) {
                                               if (/^\s*<\/IfModule>/) {
                                                   $rewrite = 0;
                                                   $num ++;
                                               } else {
                                                   s/(^\s+|\s+$)//g;
                                                   push(@{$rewrites{$file}[$num]},$_);
                                               }
                                           } elsif (/^\s*<IfModule\s+mod_rewrite\.c>/) {
                                               $rewrite = 1;
                                               $has_rewrite = 1;
                                               if ($currname eq '') {
                                                   $currname = $hostname;
                                               }
                                               $rewrites{$file}[$num] = [];
                                           }
                                       }
                                   } elsif (/^\s*<VirtualHost\s+[^:]*\:443>\s*$/) {
                                       $virtualhost = 1;
                                   }
                               }
                               close($fh);
                           }
                       }
                   }
                   if (keys(%rewrites)) {
                       my $mindiffsall;
                       foreach my $file (sort(keys(%rewrites))) {
                           if (ref($rewrites{$file}) eq 'ARRAY') {
                               my $mindiffs;
                               for (my $i=0; $i<@{$rewrites{$file}}; $i++) {
                                   if (ref($rewrites{$file}[$i]) eq 'ARRAY') {
                                       my @diffs = &compare_arrays($rewrites{$file}[$i],\@rewritessl);
                                       if (@diffs == 0) {
                                           $fixapachessl = 0;
                                           $mindiffs = 0;
                                           $rewritenum = 1+$i;
                                           last;
                                       } else {
                                           if ($mindiffs eq '') {
                                               $mindiffs = scalar(@diffs);
                                               $rewritenum = 1+$i; 
                                           } elsif (scalar(@diffs) <= $mindiffs) {
                                               $mindiffs = scalar(@diffs);
                                               $rewritenum = 1+$i;
                                           }
                                       }
                                   }
                               }
                               if ($mindiffsall eq '') {
                                   $mindiffsall = $mindiffs;
                                   $has_std = $file;
                               } elsif ($mindiffs <= $mindiffsall) {
                                   $mindiffsall = $mindiffs;
                                   $has_std = $file;
                               }
                               if ($mindiffsall == 0) {
                                   $nochgstd = 1;
                               }
                           }
                       }
                   } elsif (keys(%vhostonly) > 0) {
                       if (($has_int ne '') && (exists($vhostonly{$has_int}))) {
                           $has_std = $has_int;
                       }
                   }
                   if (@actualint) {
                       my @diffs = &compare_arrays(\@actualint,\@intssl);
                       if (@diffs) {
                           $fixapachessl = 1;
                       } else {
                           $nochgint = 1;
                       }
                   } else {
                       $fixapachessl = 1;
                 }                  }
             }              }
         }          }
         unless ($fixapachessl) {          unless ($fixapachessl) {
             if ($distro =~ /^(debian|ubuntu)(\d+)$/) {              if ($distro =~ /^(debian|ubuntu)(\d+)$/) {
                 unless ((-l '/etc/apache2/sites-enabled/loncapassl.conf') &&                  my $enabled_dir = '/etc/apache2/sites-enabled';
                         (readlink('/etc/apache2/sites-enabled/loncapassl.conf') eq '/etc/apache2/sites-available/loncapassl.conf')) {                  if (keys(%sslfiles)) {
                     print_and_log(&mt("Warning, use: 'sudo a2ensite loncapassl.conf' to activate LON-CAPA SSL Apache config\n"));                      foreach my $key (sort(keys(%sslfiles))) {
                           if (ref($sslfiles{$key}) eq 'HASH') {
                               foreach my $file (sort(keys(%{$sslfiles{$key}}))) {
                                   unless ((-l "$enabled_dir/$file") &&
                                           (readlink("$enabled_dir/$file") eq "$ssldir/$file")) {
                                       print_and_log(&mt("Warning, use: 'sudo a2ensite $file' to activate LON-CAPA SSL Apache config\n"));
                                   }
                               }
                           }
                       }
                 }                  }
             }              }
         }          }
     }      }
     return $fixapachessl;      return ($fixapachessl,\%sslfiles,$has_std,$has_int,$rewritenum,$nochgstd,$nochgint);
   }
   
   #
   # compare_arrays() expects two refs to arrays as args.
   #
   # The contents of the two arrays are compared, and if they
   # are different, and array of the differences is returned.
   #
   
   sub compare_arrays {
       my ($arrayref1,$arrayref2) = @_;
       my (@difference,%count);
       @difference = ();
       %count = ();
       if ((ref($arrayref1) eq 'ARRAY') && (ref($arrayref2) eq 'ARRAY')) {
           foreach my $element (@{$arrayref1}, @{$arrayref2}) { $count{$element}++; }
           foreach my $element (keys(%count)) {
               if ($count{$element} == 1) {
                   push(@difference,$element);
               }
           }
       }
       return @difference;
 }  }
   
 sub chksrvcs {  sub chksrvcs {
Line 1365  print "\n".&mt('Checking system status . Line 1672  print "\n".&mt('Checking system status .
 my $dsn = "DBI:mysql:database=mysql";  my $dsn = "DBI:mysql:database=mysql";
 my ($distro,$gotprereqs,$localecmd,$packagecmd,$updatecmd,$installnow,$mysqlrestart,  my ($distro,$gotprereqs,$localecmd,$packagecmd,$updatecmd,$installnow,$mysqlrestart,
     $recommended,$dbh,$has_pass,$has_lcdb,$downloadstatus,$filetouse,$production,      $recommended,$dbh,$has_pass,$has_lcdb,$downloadstatus,$filetouse,$production,
     $testing,$apachefw,$uses_systemctl,$hostname) = &check_required($instdir,$dsn);      $testing,$apachefw,$uses_systemctl,$hostname,$hostip,$sslhostsfiles,$has_std,
       $has_int,$rewritenum,$nochgstd,$nochgint) = &check_required($instdir,$dsn);
 if ($distro eq '') {  if ($distro eq '') {
     print "\n".&mt('Linux distribution could not be verified as a supported distribution.')."\n".      print "\n".&mt('Linux distribution could not be verified as a supported distribution.')."\n".
           &mt('The following are supported: [_1].',            &mt('The following are supported: [_1].',
Line 1543  if ($callsub{'apache'}) { Line 1851  if ($callsub{'apache'}) {
 }  }
   
 if ($callsub{'apachessl'}) {  if ($callsub{'apachessl'}) {
       my $targetdir = '/etc/httpd/conf.d';
     if ($distro =~ /^(suse|sles)/) {      if ($distro =~ /^(suse|sles)/) {
         &copy_apache_sslconf_file($instdir,'/etc/apache2/vhosts.d',$hostname);          $targetdir = '/etc/apache2/vhosts.d';
     } elsif ($distro =~ /^(debian|ubuntu)/) {      } elsif ($distro =~ /^(debian|ubuntu)/) {
         my $apache2_sites_available_dir = '/etc/apache2/sites-available';          $targetdir = '/etc/apache2/sites-available';
         if (&copy_apache_sslconf_file($instdir,$apache2_sites_available_dir,$hostname)) {      }
             my $apache2_sites_enabled_dir = '/etc/apache2/sites-enabled';      my ($new_rewrite,$new_int) = 
             my $made_symlink =  eval { symlink("$apache2_sites_available_dir/loncapassl.conf","$apache2_sites_enabled_dir/loncapassl.conf"); 1 };          &copy_apache_sslconf_files($distro,$hostname,$hostip,$instdir,$targetdir,$sslhostsfiles,
             if ($made_symlink) {                                     $has_std,$has_int,$rewritenum,$nochgstd,$nochgint); 
                 print_and_log(&mt('Enabling "[_1]" Apache SSL configuration.','loncapassl.conf')."\n");        if ($distro =~ /^(debian|ubuntu)/) {
           my $apache2_sites_enabled_dir = '/etc/apache2/sites-enabled';
           if (-d $apache2_sites_enabled_dir) {  
               if ($has_std ne '') {
                   unless ((-l "$apache2_sites_enabled_dir/$has_std") && (readlink(("$apache2_sites_enabled_dir/$has_std") eq "$targetdir/$has_std"))) {
                       my $made_symlink =  eval { symlink("$targetdir/$has_std","$apache2_sites_enabled_dir/$has_std"); 1};
                       if ($made_symlink) {
                           print_and_log(&mt('Enabling "[_1]" Apache SSL configuration.',$has_std)."\n");
                       }
                   }
               }
               if (($has_int ne '') && ($has_int ne $has_std)) {
                   unless ((-l "$apache2_sites_enabled_dir/$has_int") && (readlink("$apache2_sites_enabled_dir/$has_int") eq "$targetdir/$has_int")) {
                       my $made_symlink =  eval { symlink("$targetdir/$has_int","$apache2_sites_enabled_dir/$has_int"); 1 };
                       if ($made_symlink) {
                           print_and_log(&mt('Enabling "[_1]" Apache SSL configuration.',$has_int)."\n");
                       }
                   }
             }              }
         }          }
     } else {  
         &copy_apache_sslconf_file($instdir,'/etc/httpd/conf.d',$hostname);  
     }      }
     print_and_log("\n");      print_and_log("\n");
 } else {  } else {
Line 2061  sub copy_httpd_conf { Line 2385  sub copy_httpd_conf {
   
 ###############################################  ###############################################
 ##  ##
 ## Copy/Modify loncapassl.conf  ## Copy loncapassl.conf and sslrewrite.conf
 ##  ##
 ###############################################  ###############################################
   
 sub copy_apache_sslconf_file {  #
     my ($instdir,$targetdir,$hostname) = @_;  # The Apache SSL configuration used by LON-CAPA is contained in
     my ($success,$error);  # two files: sslrewrite.conf and loncapassl.conf.
   #
   # Starting with LON-CAPA 2.12, name-based virtual hosts are used
   # with port 443. The default virtual host (i.e., the one listed
   # first) is for the server's standard hostname, and that is the one 
   # which will respond to client browser requests for https:// pages. 
   #
   # Accordingly, a system administrator will need to edit the config
   # config file to include paths to a signed SSL certificate (public), 
   # chain (public) and key (private) pem files. The certificate should
   # have been signed by a recognized certificate authority ((e.g., 
   # InCommon or Let's Encrypt).
   #  
   # The sslrewrite.conf file contains the rewrite configuration for
   # the default virtual host. The rewrite rules defined are used to 
   # allow internal HEAD requests to /cgi-bin/mimetex.cgi to be served
   # http://, in order to support vertical alignment of mimetex images
   # (one of the options for rendering Math content); (b) allow requests
   # for certain URLs (external resource, and syllabus, if external URL
   # used) to be served http:// to accommodate the use of iframes which 
   # would otherwise result in browser blocking of mixed active content.
   #
   # The loncapassl.conf file contains the configuration for the  
   # "internal" virtual host, which will respond to requests for https://
   # pages from other LON-CAPA servers in the network to which the node
   # belongs. The ServerName is internal-<hostname> where <hostname>
   # is the server's hostname. There is no need to create a DNS entry 
   # for internal-<hostname>, as LON-CAPA 2.12 automatically performs
   # the required hostname to IP mapping.
   # 
   # Requests to /raw on the "internal" virtual host require a valid
   # SSL client certificate, signed by the certificate authority
   # for the LON-CAPA network to which the node belongs.
   # 
   # The configuration file to which the contents of sslrewrite.conf
   # and loncapassl.conf will be written will have either been identified
   # when &chkapachessl() was run, or if no files were found with
   # existing rewrite blocks, then a candidate file will be chosen
   # from the .conf files containing VirtualHosts definitions.
   # If there is more than one suitable candidate file, the system
   # administrator will be prompted to select from the available files.
   #
   # If there are no files containing VirtualHosts definitions, then
   # <VirtualHost *:443> </VirtualHost> blocks will be appended to
   # the standard Apache SSL config for the particular distro:
   # ssl.conf for RHEL/CentOS/Scientific/Fedora, vhost-ssl.conf
   # for SuSE/SLES, and default-ssl.conf for Ubuntu.
   #
   # Once a file is selected, the contents of sslrewrite.conf and
   # loncapassl.conf are compared with appropriate blocks in the file
   # and the user will be prompted to agree to insertion of missing lines
   # and/or deletion of surplus lines.
   #
   
   sub copy_apache_sslconf_files {
       my ($distro,$hostname,$hostip,$instdir,$targetdir,$targetfilesref,
           $has_std,$has_int,$rewritenum,$nochgstd,$nochgint) = @_;
       my ($new_std,$new_int);
       my (@internal,@standard,%int_by_linenum,%int_by_linetext,
           %rule_by_linenum,%rule_by_linetext,%foundint);
     if (-e "$instdir/loncapassl.conf") {      if (-e "$instdir/loncapassl.conf") {
         if (open(my $fh,'<',"$instdir/loncapassl.conf")) {          if (open(my $fh,'<',"$instdir/loncapassl.conf")) {
             if (open(my $out,'>',"$targetdir/loncapassl.conf")) {              my $num = 1;
                 while (<$fh>) {              while (<$fh>) {
                     if (/^\QServerName internal-\E/) {                  chomp();
                         chomp();                  if (/^ServerName/) {
                         s/^(\QServerName internal-\E)(.*)$/$1$hostname\n/;                      s/(\Qinternal-{[[[[Hostname]]]]}\E)/internal-$hostname/;
                   }
                   push(@internal,$_);
                   $int_by_linenum{$num} = $_;
                   s/(^\s+|\s+$)//g;
                   push(@{$int_by_linetext{$_}},$num);
                   $num ++;
               }
               close($fh);
           }
       }
       if (-e "$instdir/sslrewrite.conf") {
           if (open(my $fh,'<',"$instdir/sslrewrite.conf")) {
               my $num = 1;
               while (<$fh>) {
                   chomp();
                   if (/\Q{[[[[HostIP]]]]}\E/) {
                       s/(\QRewriteCond %{REMOTE_ADDR} {[[[[HostIP]]]]}\E)/RewriteCond %{REMOTE_ADDR} $hostip/;
                   }
                   push(@standard,$_);
                   $rule_by_linenum{$num} = $_;
                   s/(^\s+|\s+$)//g;
                   push(@{$rule_by_linetext{$_}},$num);
                   $num ++;
               }
               close($fh);
           }
       }
       if (!$nochgstd) {
           if ($has_std eq '') {
               my $file;
               if ($has_int ne '') {
                   if (open(my $fh,'<',"$targetdir/$has_int")) {
                       my @saved = <$fh>;
                       close($fh);
                       if (open(my $fhout, '>',"$targetdir/$has_int")) {
                           print $fhout "<VirtualHost *:443>\n".
                                        "ServerName $hostname\n".
                                        join("\n",@standard)."\n".
                                        "</VirtualHost>\n\n".
                                        join('',@saved);
                           close($fhout);
                           $new_int = $has_int; 
                       }
                   }
               }
           } else {
               if ($rewritenum eq '') {
                   &append_to_vhost($targetdir,$has_std,$hostname,\%rule_by_linenum,'std');
                   $new_std = $has_std;
               } else {
                   $new_std = &modify_ssl_config($targetdir,$has_std,$hostname,$rewritenum,
                                                 \%rule_by_linetext,\%rule_by_linenum,'std');
               }
           }
       }
       if (!$nochgint) {
           if ($has_int eq '') {
               if ($has_std ne '') {
                   if (open(my $fhout,'>>',"$targetdir/$has_std")) {
                       print $fhout "\n".join("\n",@internal)."\n";
                       close($fhout);
                       $new_int = $has_std;
                   }
               }
           } else {
               $new_int = &modify_ssl_config($targetdir,$has_int,$hostname,$rewritenum,\%int_by_linetext,\%int_by_linenum,'int');
           }
       }
       if (($has_std eq '') && ($has_int eq '')) {
           my ($file,$numfiles) = &get_sslconf_filename($distro,$targetdir,$targetfilesref);
           if ($numfiles == 0) { 
               if (open(my $fhout, '>>', "$targetdir/$file")) {
                   print $fhout "<VirtualHost *:443>\n".
                                "ServerName $hostname\n".
                                join("\n",@standard)."\n".
                                "</VirtualHost>\n\n".
                                join("\n",@internal)."\n";
                   close($fhout);
                   $new_std = $file;
                   $new_int = $file;
               }
           } elsif ($numfiles == 1) {
               &append_to_vhost($targetdir,$file,$hostname,\%rule_by_linenum,'std');
               if (open(my $fhout, '>>', "$targetdir/$file")) {
                   print $fhout "\n".join("\n",@internal)."\n";
                   close($fhout);
                   $new_std = $file;
                   $new_int = $file;
               }
           } elsif ($numfiles == -1) {
               print_and_log(&mt('Failed to copy contents of [_1] or [_2] to a file in [_3]',
                                 "'loncapassl.conf'","'sslrewrite.conf'","'$targetdir'")."\n");
           }
       }
       if ($nochgstd) {
           print_and_log(&mt('No change required to file: [_1] in [_2], (no difference between [_3] and rewrite block.)',
                             "'$has_std'","'$targetdir'","'sslrewrite.conf'"));
       }
       if ($nochgint) {
           print_and_log(&mt('No change required to file: [_1] in [_2], (no difference between [_3] and virtualhost block.)',
                             "'$has_int'","'$targetdir'","'loncapassl.conf'"));
       }
       if ($new_int) {
           print_and_log(&mt('Successfully copied contents of [_1] to [_2].',"'loncapassl.conf'","'$targetdir/$new_int'")."\n");
           chmod(0444,"$targetdir/loncapassl.conf");
       }
       if ($new_std) {
           print_and_log(&mt('Successfully copied contents of [_1] to [_2].',"'sslrewrite.conf'","'$targetdir/$new_std'")."\n");
           chmod(0444,"$targetdir/loncapassl.conf");
       }
       return ($new_int,$new_std);
   }
   
   #
   # append_to_vhost() is called to add rewrite rules (in a 
   # <IfModule +mod_rewrite.c> </IfModule> block), provided
   # in the sslrewrite.conf configuration file, to an Apache
   # SSL configuration file within a VirtualHost for port 443
   # (for server's public-facing hostname).
   #
   sub append_to_vhost {
       my ($targetdir,$filename,$hostname,$by_linenum,$type) = @_;
       return unless (ref($by_linenum) eq 'HASH');
       my ($startvhost,$endvhost);
       if (-e "$targetdir/$filename") {
           my (@lines,$currname,$virtualhost,$hasname);
           if (open(my $fh,'<',"$targetdir/$filename")) {
               my $currline = 0;
               while (<$fh>) {
                   $currline ++;
                   push(@lines,$_);
                   chomp();
                   s/(^\s+|\s+$)//g;
                   if (/^<VirtualHost\s+[^:]*\:443>/) {
                       $virtualhost = 1;
                       unless ($endvhost) {
                           $startvhost = $currline;
                     }                      }
                     print $out $_;  
                 }                  }
                 $success = 1;                  if ($virtualhost) {
                       if (/^ServerName\s+([^\s]+)\s*$/) {
                           $currname = $1;
                           unless ($endvhost) {
                               if ((($currname eq '') || ($currname eq $hostname)) && ($type eq 'std')) {
                                   $hasname = 1;
                               }
                           }
                       }
                       if (/^<\/VirtualHost>/) {
                           $virtualhost = 0;
                           unless ($endvhost) {
                               if (((($currname eq '') || ($currname eq $hostname)) && ($type eq 'std')) ||
                                   (($currname eq 'internal-'.$hostname) && ($type eq 'int'))) { 
                                   $endvhost = $currline;
                               } else {
                                   undef($startvhost);  
                               }
                           }
                       }
                   }
               }
               close($fh);
           }
           if ($endvhost) {
               if (open(my $fout,'>',"$targetdir/$filename")) {
                   for (my $i=0; $i<@lines; $i++) {
                       if ($i == $startvhost) {
                           unless (($hasname) && ($type eq 'std')) {
                               print $fout "ServerName $hostname\n";
                           }
                       }
                       if ($i == $endvhost-1) {
                           foreach my $item (sort { $a <=> $b } keys(%{$by_linenum})) {
                               print $fout $by_linenum->{$item}."\n";
                           }
                       }
                       print $fout $lines[$i];
                   }
                   close($fout);
               }
           }
       }
       return $endvhost;
   }
   
   #
   # get_sslconf_filename() is called when the Apache SSL configuration
   # option has been selected and there are no files containing
   # VirtualHost definitions containing rewrite blocks,
   # 
   # In this case get_sslconf_filename() is used to chose from the 
   # available .conf files containing VirtualHosts definitions. If
   # there is ambiguity about which file to use, &apacheconf_choice()
   # will be called to prompt the user to choose one of the possible
   # files.
   #
   
   sub get_sslconf_filename {
       my ($distro,$targetdir,$targetfilesref) = @_;
       my ($configfile,$numfiles,@possfiles);
       if (ref($targetfilesref) eq 'HASH') {
           if (keys(%{$targetfilesref}) > 0) {
               foreach my $name (sort(keys(%{$targetfilesref}))) {
                   if (ref($targetfilesref->{$name}) eq 'HASH') {
                       foreach my $file (sort(keys(%{$targetfilesref->{$name}}))) {
                           next if ($file eq '');
                           next if (!-e "$targetdir/$file");
                           unless (grep(/^\Q$file\E$/,@possfiles)) {
                               push(@possfiles,$file);
                           }
                       }
                   }
               }
           }
           if (@possfiles == 0) {
               $configfile = 'ssl.conf';
               if ($distro =~ /^(suse|sles)/) {
                   $configfile = 'vhost-ssl.conf';
               } elsif ($distro =~ /^(debian|ubuntu)/) {
                   $configfile = 'default-ssl.conf';
               }
               $numfiles = 0;
               print &mt('No configuration files in [_1] contain a <VirtualHost *:443> </VirtualHost> block which can be used to house Apache rewrite rules from https to http.',$targetdir)."\n\n".
                     &mt('Accordingly, the contents of sslrewrite.conf will be included in a <VirtualHost *:443> </VirtualHost> block which will be added to a file named: [_1].',$configfile)."\n\n";
           } elsif (@possfiles == 1) {
               $configfile = $possfiles[0];
               $numfiles = 1;
               print &mt('A single configuration file in [_1] contains a <VirtualHost *:443> </VirtualHost> block.',$targetdir)."\n".
                     &mt('The contents of sslrewrite.conf will be added to this block.')."\n\n";
           } else {
               print &mt('More than one Apache config file contains a <VirtualHost *:443> </VirtualHost> block.')."\n\n".&mt('The possible files are:')."\n";
               my $counter = 1;
               my $max = scalar(@possfiles);
               foreach my $file (@possfiles) {
                   print "$counter. $file\n";
                   $counter ++;
               }
               print "\n".&mt('Enter a number between 1 and [_1] to indicate which file should be modified to include the contents of sslrewrite.conf.',$max)."\n";
               my $choice = &apacheconf_choice($max);
               if (($choice =~ /^\d+$/) && ($choice >= 1) && ($choice <= $max)) {
                   $configfile = $possfiles[$choice-1];
                   $numfiles = 1; 
             } else {              } else {
                 $error = "Could not write to $targetdir/loncapassl.conf";                  $numfiles = -1;
             }              }
         } else {  
             $error = "Could not read from $instdir/loncapassl.conf";  
         }          }
     } else {  
         $error = "File to copy from: $instdir/loncapassl.conf does not exist";  
     }      }
     if ($success) {      return ($configfile,$numfiles);
         print_and_log(&mt('Successfully copied [_1] to [_2].',"'loncapassl.conf'","'$targetdir/loncapassl.conf'")."\n");  }
         chmod(0444,"$targetdir/loncapassl.conf");  
     } else {  #
         print_and_log(&mt('Failed to copy [_1] to [_2].',"'loncapassl.conf'","'$targetdir/loncapassl.conf'")."\n");  # &apacheconf_choice() prompts a user to choose an integer between 1 and the  
         if ($error) {  # maximum number of available of possible Apache SSL config files found
             print_and_log("$error\n");  # at the distros standard location for Apache config files containing
   # VirtualHost definitions.
   #
   # This routine is called recursively until the user enters a valid integer.
   #
   
   sub apacheconf_choice {
       my ($max) = @_;
       my $choice = <STDIN>;
       chomp($choice);
       $choice =~ s/(^\s+|\s+$)//g;
       my $configfile;
       if (($choice =~ /^\d+$/) && ($choice >= 1) && ($choice <= $max)) {
           $configfile = $choice;
       } 
       while ($configfile eq '') {
           print &mt('Invalid choice.  Please enter a number between 1 and [_1].',$max)."\n";
           $configfile = &apacheconf_choice($max);
       }
       print "\n";
       return $configfile;
   }
   
   #
   # &modify_ssl_config() is called to modify the contents of an Apache SSL config
   # file so that it has two <VirtualHost *:443> </VirtualHost> blocks containing
   # (a) the default VirtualHost with the <IfModule mod_rewrite.c> </IfModule> block 
   # provided in sslrewrites.conf, and (b) an "internal" VirtualHost with the 
   # content provided in loncapassl.conf.
   #
   # This routine will prompted you to agree to insertion of lines present in the
   # shipped conf file, but missing from the local config file, and also for
   # deletion of lines present in the local config file, but not required in
   # the shipped conf file.
   # 
    
   sub modify_ssl_config {
       my ($targetdir,$filename,$hostname,$rewritenum,$by_linetext,$by_linenum,$type) = @_;
       return unless ((ref($by_linetext) eq 'HASH') && (ref($by_linenum) eq 'HASH'));
       if (-e "$targetdir/$filename") {
           my (@lines,$virtualhost,$currname,$rewrite);
           if (open(my $fh,'<',"$targetdir/$filename")) {
               my %found;
               my %possible;
               my $currline = 0;
               my $rewritecount = 0;
               while (<$fh>) {
                   $currline ++;
                   push(@lines,$_);
                   chomp();
                   s/(^\s+|\s+$)//g;
                   if (/^\s*<VirtualHost\s+[^:]*\:443>\s*$/) {
                       $virtualhost = 1;
                   }
                   if ($virtualhost) {
                       if ((exists($by_linetext->{$_})) && (ref($by_linetext->{$_}) eq 'ARRAY') &&
                           (@{$by_linetext->{$_}} > 0)) {
                           $possible{$currline} = shift(@{$by_linetext->{$_}});
                       } 
                       if (/^\s*<\/VirtualHost>/) {
                           if ((($currname eq 'internal-'.$hostname) && ($type eq 'int')) ||
                               ((($currname eq $hostname) || ($currname eq '')) && ($type eq 'std') &&
                                 ($rewritecount == $rewritenum))) {
                               %found = (%found,%possible);
                           } else {
                               foreach my $line (sort {$b <=> $a } keys(%possible)) {
                                   my $num = $possible{$line};
                                   if (ref($by_linetext->{$by_linenum->{$num}}) eq 'ARRAY') { 
                                       unshift(@{$by_linetext->{$by_linenum->{$num}}},$num);
                                   }
                               } 
                           }
                           undef(%possible);
                           $virtualhost = 0;
                           $currname = '';
                       } elsif (/^\s*ServerName\s+([^\s]+)\s*$/) {
                           $currname = $1;
                       } elsif (/^\s*<IfModule\s+mod_rewrite\.c>/) {
                           $rewrite = 1;
                       } elsif (/^\s*<\/IfModule>/) {
                           $rewritecount ++;
                           $rewrite = 0;
                       }
                   }
               }
               close($fh);
               if (open(my $fout,'>',"$targetdir/$filename")) {
                   my $currline = 0;
                   my ($lastfound,$done);
                   my $numfound = 0;
                   foreach my $line (@lines) {
                       $currline ++;
                       if ($done) {
                           print $fout $line;
                       } elsif ($lastfound) {
                           if ($found{$currline}) {
                               for (my $i=$lastfound+1; $i<$found{$currline}; $i++) {
                                   print &mt('The following line is missing from the current <VirtualHost *:443> </VirtualHost> block:')."\n".
                                         $by_linenum->{$i}."\n".
                                         &mt('Add this line? ~[Y/n~]');
                                   if (&get_user_selection(1)) {
                                       print $fout $by_linenum->{$i}."\n";
                                   }
                               }
                               $numfound ++;
                               $lastfound = $found{$currline};
                               print $fout $line;
                               if ($numfound == scalar(keys(%found))) {
                                   $done = 1;
                                   for (my $i=$found{$currline}+1; $i<=scalar(keys(%{$by_linenum})); $i++) {
                                       print &mt('The following line is missing from the current <VirtualHost *:443> </VirtualHost> block:')."\n".
                                             $by_linenum->{$i}."\n".
                                             &mt('Add this line? ~[Y/n~]');
                                       if (&get_user_selection(1)) {
                                           print $fout $by_linenum->{$i}."\n";
                                       }
                                   }
                               }
                           } else {
                               print &mt('The following line found within a <VirtualHost *:443> </VirtualHost> block does not match that expected by LON-CAPA:')."\n".
                                     $line.
                                     &mt('Delete this line? ~[Y/n~]');
                               if (!&get_user_selection(1)) {
                                   print $fout $line;
                               }
                           }
                       } elsif ($found{$currline}) {
                           $numfound ++;
                           $lastfound = $found{$currline};
                           for (my $i=1; $i<$found{$currline}; $i++) {
                               print &mt('The following line is missing from the current <VirtualHost *:443> </VirtualHost> block:')."\n".
                                     $by_linenum->{$i}."\n".
                                     &mt('Add this line? ~[Y/n~]');
                               if (&get_user_selection(1)) {
                                   print $fout $by_linenum->{$i}."\n";
                               }
                           }
                           print $fout $line;
                       } else {
                           print $fout $line;
                       }
                   }
                   close($fout);
               }
         }          }
     }      }
     return $success;      return $filename;
 }  }
   
 #########################################################  #########################################################

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


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