Annotation of doc/install/linux/install.pl, revision 1.45.2.21

1.1       raeburn     1: #!/usr/bin/perl
                      2: # The LearningOnline Network 
                      3: # Pre-installation script for LON-CAPA
                      4: #
                      5: # Copyright Michigan State University Board of Trustees
                      6: #
                      7: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                      8: #
                      9: # LON-CAPA is free software; you can redistribute it and/or modify
                     10: # it under the terms of the GNU General Public License as published by
                     11: # the Free Software Foundation; either version 2 of the License, or
                     12: # (at your option) any later version.
                     13: #
                     14: # LON-CAPA is distributed in the hope that it will be useful,
                     15: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     16: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     17: # GNU General Public License for more details.
                     18: #
                     19: # You should have received a copy of the GNU General Public License
                     20: # along with LON-CAPA; if not, write to the Free Software
                     21: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     22: #
                     23: # http://www.lon-capa.org/
                     24: #
                     25: 
                     26: use strict;
                     27: use File::Copy;
                     28: use Term::ReadKey;
                     29: use DBI;
1.45.2.11  raeburn    30: use File::Spec;
1.43      raeburn    31: use Cwd();
                     32: use File::Basename();
                     33: use lib File::Basename::dirname(Cwd::abs_path($0));
1.1       raeburn    34: use LCLocalization::localize;
                     35: 
                     36: # ========================================================= The language handle
                     37: 
                     38: my %languages = (
                     39:                   ar => 'Arabic', 
                     40:                   de => 'German',
                     41:                   en => 'English',
                     42:                   es => 'Spanish (Castellan)',
                     43:                   fa => 'Persian',
                     44:                   fr => 'French', 
                     45:                   he => 'Hebrew', 
                     46:                   ja => 'Japanese',
                     47:                   pt => 'Portuguese',
                     48:                   ru => 'Russian',
                     49:                   tr => 'Turkish',
                     50:                   zh => 'Chinese Simplified'
                     51:                ); 
                     52: 
                     53: use vars qw($lh $lang);
                     54: $lang = 'en';
                     55: if (@ARGV > 0) {
                     56:     foreach my $poss (keys(%languages)) {
                     57:         if ($ARGV[0] eq $poss) {
                     58:             $lang = $ARGV[0]; 
                     59:         }
                     60:     }
                     61: }
                     62: 
                     63: &get_language_handle($lang);
                     64: 
                     65: # Check user has root privs
                     66: if (0 != $<) {
                     67:     print &mt('This script must be run as root.')."\n".
                     68:           &mt('Stopping execution.')."\n";
                     69:     exit;
                     70: }
                     71: 
                     72: 
                     73: # Globals: filehandle LOG is global.
                     74: if (!open(LOG,">>loncapa_install.log")) {
                     75:     print &mt('Unable to open log file.')."\n".
                     76:           &mt('Stopping execution.')."\n";
                     77:     exit;
                     78: } else {
1.45.2.21! raeburn    79:     print LOG '$Id: install.pl,v 1.45.2.20 2024/07/27 18:40:15 raeburn Exp $'."\n";
1.1       raeburn    80: }
                     81: 
                     82: #
1.2       raeburn    83: # Helper routines and routines to establish recommended actions
1.1       raeburn    84: #
                     85: 
                     86: sub get_language_handle {
                     87:     my @languages = @_;
                     88:     $lh=LCLocalization::localize->get_handle(@languages);
                     89: }
                     90: 
                     91: sub mt (@) {
                     92:     if ($lh) {
                     93:         if ($_[0] eq '') {
                     94:             if (wantarray) {
                     95:                 return @_;
                     96:             } else {
                     97:                 return $_[0];
                     98:             }
                     99:         } else {
                    100:             return $lh->maketext(@_);
                    101:         }
                    102:     } else {
                    103:         if (wantarray) {
                    104:             return @_;
                    105:         } else {
                    106:             return $_[0];
                    107:         }
                    108:     }
                    109: }
                    110: 
                    111: sub texthash {
                    112:     my (%hash) = @_;
                    113:     foreach (keys(%hash)) {
                    114:         $hash{$_}=&mt($hash{$_});
                    115:     }
                    116:     return %hash;
                    117: }
                    118: 
                    119: 
                    120: sub skip_if_nonempty {
                    121:     my ($string,$error)=@_;
                    122:     return if (! defined($error));
                    123:     chomp($string);chomp($error);
                    124:     if ($string ne '') {
                    125:         print_and_log("$error\n".&mt('Stopping execution.')."\n");
                    126:         return 1;
                    127:     }
                    128:     return;
                    129: }
                    130: 
                    131: sub writelog {
                    132:     while ($_ = shift) {
                    133:         chomp();
                    134:         print LOG "$_\n";
                    135:     }
                    136: }
                    137: 
                    138: sub print_and_log {
                    139:     while ($_=shift) {
                    140:         chomp();
                    141:         print "$_\n";
                    142:         print LOG "$_\n";
                    143:     }
                    144: }
                    145: 
                    146: sub get_user_selection {
                    147:     my ($defaultrun) = @_;
                    148:     my $do_action = 0;
                    149:     my $choice = <STDIN>;
                    150:     chomp($choice);
                    151:     $choice =~ s/(^\s+|\s+$)//g;
                    152:     my $yes = &mt('y');
                    153:     if ($defaultrun) {
                    154:         if (($choice eq '') || ($choice =~ /^\Q$yes\E/i)) {
                    155:             $do_action = 1;
                    156:         }
                    157:     } else {
                    158:         if ($choice =~ /^\Q$yes\E/i) {
                    159:             $do_action = 1;
                    160:         }
                    161:     }
                    162:     return $do_action;
                    163: }
                    164: 
                    165: sub get_distro {
1.45.2.1  raeburn   166:     my ($distro,$gotprereqs,$updatecmd,$packagecmd,$installnow,$unknown);
1.1       raeburn   167:     $packagecmd = '/bin/rpm -q LONCAPA-prerequisites ';
1.45.2.3  raeburn   168:     if (-e '/etc/oracle-release') {
                    169:         open(IN,'</etc/oracle-release');
                    170:         my $versionstring=<IN>;
                    171:         chomp($versionstring);
                    172:         close(IN);
                    173:         if ($versionstring =~ /^Oracle Linux Server release (\d+)/) {
                    174:             my $version = $1;
                    175:             $distro = 'oracle'.$1;
                    176:             $updatecmd = 'yum install LONCAPA-prerequisites';
                    177:             $installnow = 'yum -y install LONCAPA-prerequisites';
                    178:         }
                    179:     } elsif (-e '/etc/redhat-release') {
1.1       raeburn   180:         open(IN,'</etc/redhat-release');
                    181:         my $versionstring=<IN>;
                    182:         chomp($versionstring);
                    183:         close(IN);
                    184:         if ($versionstring =~ /^Red Hat Linux release ([\d\.]+) /) {
                    185:             my $version = $1;
                    186:             if ($version=~/^7\./) {
                    187:                 $distro='redhat7';
                    188:             } elsif ($version=~/^8\./) {
                    189:                 $distro='redhat8';
                    190:             } elsif ($version=~/^9/) {
                    191:                 $distro='redhat9';
                    192:             }
                    193:         } elsif ($versionstring =~ /Fedora( Core)? release ([\d\.]+) /) {
                    194:             my $version=$2;
                    195:             if ($version - int($version) > .9) {
                    196:                 $distro = 'fedora'.(int($version)+1);
                    197:             } else {
                    198:                 $distro = 'fedora'.int($version);
                    199:             }
                    200:             $updatecmd = 'yum install LONCAPA-prerequisites';
                    201:             $installnow = 'yum -y install LONCAPA-prerequisites';
                    202:         } elsif ($versionstring =~ /Red Hat Enterprise Linux [AE]S release ([\d\.]+) /) {
                    203:             $distro = 'rhes'.$1;
                    204:             $updatecmd = 'up2date -i LONCAPA-prerequisites';
                    205:         } elsif ($versionstring =~ /Red Hat Enterprise Linux Server release (\d+)/) {
                    206:             $distro = 'rhes'.$1;
                    207:             $updatecmd = 'yum install LONCAPA-prerequisites';
                    208:             $installnow = 'yum -y install LONCAPA-prerequisites';
1.45.2.3  raeburn   209:         } elsif ($versionstring =~ /Red Hat Enterprise Linux release (\d+)/) {
                    210:             $distro = 'rhes'.$1;
                    211:             $updatecmd = 'dnf install LONCAPA-prerequisites';
                    212:             $installnow = 'dnf -y install LONCAPA-prerequisites';
1.45.2.18  raeburn   213:         } elsif ($versionstring =~ /CentOS(| Linux| Stream) release (\d+)/) {
                    214:             $distro = 'centos'.$2;
                    215:             if ($1 eq ' Stream') {
                    216:                 $distro .= '-stream';
                    217:             }
1.1       raeburn   218:             $updatecmd = 'yum install LONCAPA-prerequisites';
                    219:             $installnow = 'yum -y install LONCAPA-prerequisites';
1.22      raeburn   220:         } elsif ($versionstring =~ /Scientific Linux (?:SL )?release ([\d.]+) /) {
1.1       raeburn   221:             my $ver = $1;
                    222:             $ver =~ s/\.\d+$//;
                    223:             $distro = 'scientific'.$ver;
                    224:             $updatecmd = 'yum install LONCAPA-prerequisites';
                    225:             $installnow = 'yum -y install LONCAPA-prerequisites';
1.45.2.18  raeburn   226:         } elsif ($versionstring =~ /Rocky Linux release ([\d.]+)/) {
                    227:             my $ver = $1;
                    228:             $ver =~ s/\.\d+$//;
                    229:             $distro = 'rocky'.$ver;
                    230:             $updatecmd = 'dnf install LONCAPA-prerequisites';
                    231:             $installnow = 'dnf -y install LONCAPA-prerequisites';
                    232:         } elsif ($versionstring =~ /AlmaLinux release ([\d.]+) /) {
                    233:             my $ver = $1;
                    234:             $ver =~ s/\.\d+$//;
                    235:             $distro = 'alma'.$ver;
                    236:             $updatecmd = 'dnf install LONCAPA-prerequisites';
                    237:             $installnow = 'dnf -y install LONCAPA-prerequisites';
1.1       raeburn   238:         } else {
                    239:             print &mt('Unable to interpret [_1] to determine system type.',
                    240:                       '/etc/redhat-release')."\n";
1.45.2.1  raeburn   241:             $unknown = 1;
1.1       raeburn   242:         }
                    243:     } elsif (-e '/etc/SuSE-release') {
                    244:         open(IN,'</etc/SuSE-release');
                    245:         my $versionstring=<IN>;
                    246:         chomp($versionstring);
                    247:         close(IN);
                    248:         if ($versionstring =~ /^SUSE LINUX Enterprise Server ([\d\.]+) /i) {
                    249:             $distro='sles'.$1;
                    250:             if ($1 >= 10) {
                    251:                 $updatecmd = 'zypper install LONCAPA-prerequisites';
                    252:             } else {
                    253:                 $updatecmd = 'yast -i LONCAPA-prerequisites';
                    254:             }
                    255:         } elsif ($versionstring =~ /^SuSE Linux ([\d\.]+) /i) {
                    256:             $distro = 'suse'.$1;
1.12      raeburn   257:             $updatecmd = 'yast -i LONCAPA-prerequisites';
1.1       raeburn   258:         } elsif ($versionstring =~ /^openSUSE ([\d\.]+) /i) {
                    259:             $distro = 'suse'.$1;
                    260:             if ($1 >= 10.3 ) {
                    261:                 $updatecmd = 'zypper install LONCAPA-prerequisites';
                    262:             } else {
                    263:                 $updatecmd = 'yast -i LONCAPA-prerequisites';
                    264:             }
                    265:         } else {
                    266:             print &mt('Unable to interpret [_1] to determine system type.',
                    267:                       '/etc/SuSE-release')."\n";
1.45.2.1  raeburn   268:             $unknown = 1;
1.1       raeburn   269:         }
                    270:     } elsif (-e '/etc/issue') {
                    271:         open(IN,'</etc/issue');
                    272:         my $versionstring=<IN>;
                    273:         chomp($versionstring);
                    274:         close(IN);
                    275:         if ($versionstring =~ /^Ubuntu (\d+)\.\d+/i) {
                    276:             $distro = 'ubuntu'.$1;
                    277:             $updatecmd = 'sudo apt-get install loncapa-prerequisites';
                    278:         } elsif ($versionstring =~ /^Debian\s+GNU\/Linux\s+(\d+)\.\d+/i) {
                    279:             $distro = 'debian'.$1;
1.45.2.1  raeburn   280:             $updatecmd = 'apt-get install loncapa-prerequisites';
1.1       raeburn   281:         } elsif (-e '/etc/debian_version') {
                    282:             open(IN,'</etc/debian_version');
                    283:             my $version=<IN>;
                    284:             chomp($version);
                    285:             close(IN);
                    286:             if ($version =~ /^(\d+)\.\d+\.?\d*/) {
                    287:                 $distro='debian'.$1;
1.45.2.1  raeburn   288:                 $updatecmd = 'apt-get install loncapa-prerequisites';
1.1       raeburn   289:             } else {
                    290:                 print &mt('Unable to interpret [_1] to determine system type.',
                    291:                           '/etc/debian_version')."\n";
1.45.2.1  raeburn   292:                 $unknown = 1;
1.1       raeburn   293:             }
1.45.2.1  raeburn   294:         }
                    295:         if ($distro ne '') {
                    296:             $packagecmd = '/usr/bin/dpkg -l loncapa-prerequisites ';
1.1       raeburn   297:         }
                    298:     } elsif (-e '/etc/debian_version') {
                    299:         open(IN,'</etc/debian_version');
                    300:         my $version=<IN>;
                    301:         chomp($version);
                    302:         close(IN);
                    303:         if ($version =~  /^(\d+)\.\d+\.?\d*/) {
                    304:             $distro='debian'.$1;
                    305:             $packagecmd = '/usr/bin/dpkg -l loncapa-prerequisites ';
                    306:             $updatecmd = 'apt-get install loncapa-prerequisites';
                    307:         } else {
                    308:             print &mt('Unable to interpret [_1] to determine system type.',
                    309:                       '/etc/debian_version')."\n";
1.45.2.1  raeburn   310:             $unknown = 1;
                    311:         }
                    312:     }
                    313:     if (($distro eq '') && (!$unknown)) {
                    314:         if (-e '/etc/os-release') {
                    315:             if (open(IN,'<','/etc/os-release')) {
                    316:                 my ($id,$version);
                    317:                 while(<IN>) {
                    318:                     chomp();
                    319:                     if (/^ID="(\w+)"/) {
                    320:                         $id=$1;
                    321:                     } elsif (/^VERSION_ID="([\d\.]+)"/) {
                    322:                         $version=$1;
                    323:                     }
                    324:                 }
                    325:                 close(IN);
                    326:                 if ($id eq 'sles') {
                    327:                     my ($major,$minor) = split(/\./,$version);
                    328:                     if ($major =~ /^\d+$/) {
                    329:                         $distro = $id.$major;
                    330:                         $updatecmd = 'zypper install LONCAPA-prerequisites';
                    331:                     }
                    332:                 }
                    333:             }
                    334:             if ($distro eq '') {
                    335:                 print &mt('Unable to interpret [_1] to determine system type.',
                    336:                           '/etc/os-release')."\n";
                    337:                 $unknown = 1;
                    338:             }
                    339:         } else {
1.45.2.3  raeburn   340:             print &mt('Unknown installation: expecting a debian, ubuntu, suse, sles, redhat, fedora, scientific linux, or oracle linux system.')."\n";
1.1       raeburn   341:         }
                    342:     }
                    343:     return ($distro,$packagecmd,$updatecmd,$installnow);
                    344: }
                    345: 
                    346: sub check_prerequisites {
                    347:     my ($packagecmd,$distro) = @_;
                    348:     my $gotprereqs;
                    349:     if ($packagecmd ne '') {
                    350:         if (open(PIPE,"$packagecmd|")) {
                    351:             if ($distro =~ /^(debian|ubuntu)/) {
                    352:                 my @lines = <PIPE>;
                    353:                 chomp(@lines);
                    354:                 foreach my $line (@lines) {
                    355:                     if ($line =~ /^ii\s+loncapa-prerequisites\s+([\w\.]+)/) {
                    356:                         $gotprereqs = $1;
                    357:                     }
                    358:                 }
                    359:             } else {
                    360:                 my $line = <PIPE>;
                    361:                 chomp($line);
1.8       raeburn   362:                 if ($line =~ /^LONCAPA\-prerequisites\-([\d\-]+)\.(?:[.\w]+)$/) {
1.1       raeburn   363:                     $gotprereqs = $1;
                    364:                 }
                    365:             }
                    366:             close(PIPE);
                    367:         } else {
                    368:             print &mt('Error: could not determine if LONCAPA-prerequisites package is installed')."\n";
                    369:         }
                    370:     }
                    371:     return $gotprereqs;
                    372: }
                    373: 
1.6       raeburn   374: sub check_locale {
                    375:     my ($distro) = @_;
1.45.2.7  raeburn   376:     my ($fh,$langvar,$command,$earlyout);
1.8       raeburn   377:     $langvar = 'LANG';
1.6       raeburn   378:     if ($distro =~ /^(ubuntu|debian)/) {
                    379:         if (!open($fh,"</etc/default/locale")) {
                    380:             print &mt('Failed to open: [_1], default locale not checked.',
                    381:                       '/etc/default/locale');
1.45.2.7  raeburn   382:             $earlyout = 1;
1.6       raeburn   383:         }
1.45.2.1  raeburn   384:     } elsif ($distro =~ /^(suse|sles)(\d+)/) {
                    385:         if (($1 eq 'sles') && ($2 >= 15)) {
                    386:             if (!open($fh,"</etc/locale.conf")) {
                    387:                 print &mt('Failed to open: [_1], default locale not checked.',
                    388:                           '/etc/locale.conf');
1.45.2.7  raeburn   389:                 $earlyout = 1;
1.45.2.1  raeburn   390:             }
                    391:         } else {
                    392:             if (!open($fh,"</etc/sysconfig/language")) {
                    393:                 print &mt('Failed to open: [_1], default locale not checked.',
                    394:                           '/etc/sysconfig/language');
1.45.2.7  raeburn   395:                 $earlyout = 1;
1.45.2.1  raeburn   396:             }
                    397:             $langvar = 'RC_LANG';
1.8       raeburn   398:         }
1.24      raeburn   399:     } elsif ($distro =~ /^fedora(\d+)/) {
                    400:         if ($1 >= 18) {
                    401:             if (!open($fh,"</etc/locale.conf")) {
                    402:                 print &mt('Failed to open: [_1], default locale not checked.',
                    403:                           '/etc/locale.conf');
1.45.2.7  raeburn   404:                 $earlyout = 1;
1.24      raeburn   405:             }
                    406:         } elsif (!open($fh,"</etc/sysconfig/i18n")) {
                    407:             print &mt('Failed to open: [_1], default locale not checked.',
                    408:                       '/etc/sysconfig/i18n');
1.45.2.7  raeburn   409:             $earlyout = 1;
1.24      raeburn   410:         }
1.45.2.18  raeburn   411:     } elsif ($distro =~ /^(?:rhes|centos|scientific|oracle|rocky|alma)(\d+)/) {
1.29      raeburn   412:         if ($1 >= 7) {
                    413:             if (!open($fh,"</etc/locale.conf")) {
                    414:                 print &mt('Failed to open: [_1], default locale not checked.',
                    415:                           '/etc/locale.conf');
1.45.2.7  raeburn   416:                 $earlyout = 1;
1.29      raeburn   417:             }
                    418:         } elsif (!open($fh,"</etc/sysconfig/i18n")) {
                    419:             print &mt('Failed to open: [_1], default locale not checked.',
                    420:                       '/etc/sysconfig/i18n');
1.45.2.7  raeburn   421:             $earlyout = 1;
1.29      raeburn   422:         }
1.6       raeburn   423:     } else {
                    424:         if (!open($fh,"</etc/sysconfig/i18n")) {
                    425:             print &mt('Failed to open: [_1], default locale not checked.',
                    426:                       '/etc/sysconfig/i18n');
1.45.2.7  raeburn   427:             $earlyout = 1;
1.6       raeburn   428:         }
                    429:     }
1.45.2.7  raeburn   430:     return if ($earlyout);
1.6       raeburn   431:     my @data = <$fh>;
                    432:     chomp(@data);
                    433:     foreach my $item (@data) {
1.25      raeburn   434:         if ($item =~ /^\Q$langvar\E=\"?([^\"]*)\"?/) {
1.6       raeburn   435:             my $default = $1;
                    436:             if ($default ne 'en_US.UTF-8') {
                    437:                 if ($distro =~ /^debian/) {
1.25      raeburn   438:                     $command = 'locale-gen en_US.UTF-8'."\n".
                    439:                                'update-locale LANG=en_US.UTF-8';
1.6       raeburn   440:                 } elsif ($distro =~ /^ubuntu/) {
1.25      raeburn   441:                     $command = 'sudo locale-gen en_US.UTF-8'."\n".
                    442:                                'sudo update-locale LANG=en_US.UTF-8';
1.7       raeburn   443:                 } elsif ($distro =~ /^(suse|sles)/) {
1.45.2.3  raeburn   444:                     $command = 'yast language';
                    445:                 } elsif (-e '/usr/bin/system-config-language') {
1.6       raeburn   446:                     $command = 'system-config-language';
1.45.2.3  raeburn   447:                 } elsif (-e '/usr/bin/localectl') {
1.45.2.4  raeburn   448:                     $command = '/usr/bin/localectl set-locale LANG=en_US.UTF-8';
1.45.2.3  raeburn   449:                 } else {
                    450:                     $command = 'No standard command found';
1.6       raeburn   451:                 }
                    452:             }
                    453:             last;
                    454:         }
                    455:     }
                    456:     close($fh);
                    457:     return $command;
                    458: }
                    459: 
1.1       raeburn   460: sub check_required {
                    461:     my ($instdir,$dsn) = @_;
                    462:     my ($distro,$packagecmd,$updatecmd,$installnow) = &get_distro();
                    463:     if ($distro eq '') {
                    464:         return;
                    465:     }
                    466:     my $gotprereqs = &check_prerequisites($packagecmd,$distro); 
                    467:     if ($gotprereqs eq '') {
1.22      raeburn   468:         return ($distro,$gotprereqs,'',$packagecmd,$updatecmd);
1.6       raeburn   469:     }
                    470:     my $localecmd = &check_locale($distro);
                    471:     unless ($localecmd eq '') {
                    472:         return ($distro,$gotprereqs,$localecmd);
1.1       raeburn   473:     }
1.45.2.9  raeburn   474:     my ($mysqlon,$mysqlsetup,$mysqlrestart,$dbh,$has_pass,$mysql_unix_socket,$has_lcdb,
                    475:         %recommended,$downloadstatus,$filetouse,$production,$testing,$apachefw,
1.45.2.12  raeburn   476:         $tostop,$uses_systemctl,$mysql_has_wwwuser);
1.1       raeburn   477:     my $wwwuid = &uid_of_www();
                    478:     my $wwwgid = getgrnam('www');
                    479:     if (($wwwuid eq '') || ($wwwgid eq '')) {
                    480:         $recommended{'wwwuser'} = 1;
                    481:     }
                    482:     unless( -e "/usr/local/sbin/pwauth") {
                    483:         $recommended{'pwauth'} = 1;
                    484:     }
                    485:     $mysqlon = &check_mysql_running($distro);
                    486:     if ($mysqlon) {
1.45.2.14  raeburn   487:         ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser,$mysql_unix_socket) =
1.45.2.12  raeburn   488:             &check_mysql_setup($instdir,$dsn,$distro);
1.34      raeburn   489:         if ($mysqlsetup eq 'needsrestart') {
                    490:             $mysqlrestart = '';
                    491:             if ($distro eq 'ubuntu') {
1.45.2.19  raeburn   492:                 $mysqlrestart = 'sudo ';
1.34      raeburn   493:             }
                    494:             $mysqlrestart .= 'service mysql restart';
                    495:             return ($distro,$gotprereqs,$localecmd,$packagecmd,$updatecmd,$installnow,$mysqlrestart);
1.1       raeburn   496:         } else {
1.34      raeburn   497:             if ($mysqlsetup eq 'noroot') {
1.1       raeburn   498:                 $recommended{'mysqlperms'} = 1;
1.34      raeburn   499:             } else {
                    500:                 unless ($mysql_has_wwwuser) {
                    501:                     $recommended{'mysqlperms'} = 1;
                    502:                 }
                    503:             }
                    504:             if ($dbh) {
                    505:                 $has_lcdb = &check_loncapa_mysqldb($dbh);
                    506:             }
                    507:             unless ($has_lcdb) {
                    508:                 $recommended{'mysql'} = 1;
1.1       raeburn   509:             }
                    510:         }
                    511:     }
1.5       raeburn   512:     ($recommended{'firewall'},$apachefw) = &chkfirewall($distro);
1.35      raeburn   513:     ($recommended{'runlevels'},$tostop,$uses_systemctl) = &chkconfig($distro,$instdir);
1.45.2.20  raeburn   514:     if ((ref($uses_systemctl) eq 'HASH') && ($uses_systemctl->{'apache'})) {
                    515:         $recommended{'systemd'} = &check_systemd_security($distro);
                    516:     }
1.1       raeburn   517:     $recommended{'apache'} = &chkapache($distro,$instdir);
                    518:     $recommended{'stopsrvcs'} = &chksrvcs($distro,$tostop);
                    519:     ($recommended{'download'},$downloadstatus,$filetouse,$production,$testing) 
1.45.2.16  raeburn   520:         = &need_download($distro,$instdir);
1.6       raeburn   521:     return ($distro,$gotprereqs,$localecmd,$packagecmd,$updatecmd,$installnow,
1.45.2.9  raeburn   522:             $mysqlrestart,\%recommended,$dbh,$has_pass,$mysql_unix_socket,
                    523:             $has_lcdb,$downloadstatus,$filetouse,$production,$testing,$apachefw,
                    524:             $uses_systemctl);
1.1       raeburn   525: }
                    526: 
                    527: sub check_mysql_running {
                    528:     my ($distro) = @_;
1.23      raeburn   529:     my $use_systemctl;
1.1       raeburn   530:     my $mysqldaemon ='mysqld';
                    531:     if ($distro =~ /^(suse|sles|debian|ubuntu)/) {
                    532:         $mysqldaemon = 'mysql';
                    533:     }
1.6       raeburn   534:     my $process = 'mysqld_safe';
                    535:     my $proc_owner = 'root';
                    536:     if ($distro =~ /^ubuntu(\w+)/) {
                    537:         if ($1 >= 10) {
                    538:             $process = 'mysqld';
                    539:             $proc_owner = 'mysql';
                    540:         }
1.45.2.20  raeburn   541:         if ($1 >= 16) {
                    542:             $use_systemctl = 1;
                    543:         }
1.45.2.19  raeburn   544:     } elsif ($distro =~ /^debian(\w+)/) {
                    545:         if ($1 >= 10) {
                    546:             $process = 'mysql';
                    547:             $proc_owner = 'mysql';
                    548:         }
                    549:         if ($1 >= 11) {
                    550:             $mysqldaemon = 'mariadb';
                    551:         }
1.45.2.20  raeburn   552:         if ($1 >= 9) {
                    553:             $use_systemctl = 1;
                    554:         }
1.35      raeburn   555:     } elsif ($distro =~ /^fedora(\d+)/) {
1.23      raeburn   556:         if ($1 >= 16) {
                    557:             $process = 'mysqld';
                    558:             $proc_owner = 'mysql';
                    559:             $use_systemctl = 1;
                    560:         }
1.39      raeburn   561:         if ($1 >= 19) {
1.37      raeburn   562:             $mysqldaemon ='mariadb';
                    563:         }
1.45.2.17  raeburn   564:         if ($1 >= 34) {
                    565:             $process = 'mariadb';
                    566:         }
1.45.2.18  raeburn   567:     } elsif ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
1.29      raeburn   568:         if ($1 >= 7) {
                    569:             $mysqldaemon ='mariadb';
                    570:             $process = 'mysqld';
                    571:             $proc_owner = 'mysql';
                    572:             $use_systemctl = 1;
                    573:         }
1.45.2.19  raeburn   574:         if ($1 >= 9) {
                    575:             $process = 'mariadb';
                    576:         }
1.35      raeburn   577:     } elsif ($distro =~ /^sles(\d+)/) {
                    578:         if ($1 >= 12) {
                    579:             $use_systemctl = 1;
1.42      raeburn   580:             $proc_owner = 'mysql';
                    581:             $process = 'mysqld';
1.35      raeburn   582:         }
1.45.2.1  raeburn   583:         if ($1 >= 15) {
                    584:             $mysqldaemon ='mariadb';
                    585:         }
1.35      raeburn   586:     } elsif ($distro =~ /^suse(\d+)/) {
                    587:         if ($1 >= 13) {
                    588:             $use_systemctl = 1;
                    589:         }
1.29      raeburn   590:     }
1.35      raeburn   591:     if (open(PIPE,"ps -ef |grep $process |grep ^$proc_owner |grep -v grep 2>&1 |")) {
1.1       raeburn   592:         my $status = <PIPE>;
                    593:         close(PIPE);
                    594:         chomp($status);
1.6       raeburn   595:         if ($status =~ /^\Q$proc_owner\E\s+\d+\s+/) {
1.1       raeburn   596:             print_and_log(&mt('MySQL is running.')."\n");
                    597:             return 1;
                    598:         } else {
1.23      raeburn   599:             if ($use_systemctl) {
                    600:                 system("/bin/systemctl start $mysqldaemon.service >/dev/null 2>&1 ");
                    601:             } else {
                    602:                 system("/etc/init.d/$mysqldaemon start >/dev/null 2>&1 ");
                    603:             }
1.1       raeburn   604:             print_and_log(&mt('Waiting for MySQL to start.')."\n");
                    605:             sleep 5;
1.12      raeburn   606:             if (open(PIPE,"ps -ef |grep $process |grep -v grep 2>&1 |")) {
                    607:                 $status = <PIPE>;
1.1       raeburn   608:                 close(PIPE);
                    609:                 chomp($status);
1.12      raeburn   610:                 if ($status =~ /^\Q$proc_owner\E\s+\d+\s+/) {
1.1       raeburn   611:                     print_and_log(&mt('MySQL is running.')."\n");
                    612:                     return 1;
                    613:                 } else {
1.12      raeburn   614:                     print_and_log(&mt('Still waiting for MySQL to start.')."\n");
                    615:                     sleep 5;
                    616:                     if (open(PIPE,"ps -ef |grep $process |grep -v grep 2>&1 |")) {
                    617:                         $status = <PIPE>;
                    618:                         close(PIPE);
                    619:                         chomp($status);
                    620:                         if ($status =~ /^\Q$proc_owner\E\s+\d+\s+/) {
                    621:                             print_and_log(&mt('MySQL is running.')."\n");
                    622:                             return 1;
                    623:                         } else {
                    624:                             print_and_log(&mt('Given up waiting for MySQL to start.')."\n"); 
                    625:                         }
                    626:                     }
1.1       raeburn   627:                 }
                    628:             }
                    629:         }
                    630:     } else {
                    631:         print &mt('Could not determine if MySQL is running.')."\n";
                    632:     }
                    633:     return;
                    634: }
                    635: 
                    636: sub chkconfig {
1.8       raeburn   637:     my ($distro,$instdir) = @_;
1.23      raeburn   638:     my (%needfix,%tostop,%uses_systemctl);
1.1       raeburn   639:     my $checker_bin = '/sbin/chkconfig';
1.23      raeburn   640:     my $sysctl_bin = '/bin/systemctl';
1.6       raeburn   641:     my %daemon = (
                    642:                   mysql     => 'mysqld',
                    643:                   apache    => 'httpd',
                    644:                   cups      => 'cups',
                    645:                   ntp       => 'ntpd',
                    646:                   memcached => 'memcached',
                    647:     );
1.1       raeburn   648:     my @runlevels = qw/3 4 5/;
                    649:     my @norunlevels = qw/0 1 6/;
                    650:     if ($distro =~ /^(suse|sles)/) {
                    651:         @runlevels = qw/3 5/;
                    652:         @norunlevels = qw/0 2 1 6/;
1.6       raeburn   653:         $daemon{'mysql'} = 'mysql';
                    654:         $daemon{'apache'} = 'apache2';
1.8       raeburn   655:         $daemon{'ntp'}    = 'ntp';
1.1       raeburn   656:         if ($distro =~ /^(suse|sles)9/) {
1.6       raeburn   657:             $daemon{'apache'} = 'apache';
1.1       raeburn   658:         }
1.35      raeburn   659:         if ($distro =~ /^(suse|sles)([\d\.]+)/) {
                    660:             my $name = $1;
                    661:             my $num = $2;
                    662:             if ($num > 11) {
1.26      raeburn   663:                 $uses_systemctl{'apache'} = 1;
1.35      raeburn   664:                 if (($name eq 'sles') || ($name eq 'suse' && $num >= 13.2)) {
                    665:                     $uses_systemctl{'mysql'} = 1;
                    666:                     $uses_systemctl{'ntp'} = 1;
                    667:                     $uses_systemctl{'cups'} = 1;
                    668:                     $uses_systemctl{'memcached'} = 1;
1.45.2.1  raeburn   669:                     if (($name eq 'sles') && ($num >= 15)) {
                    670:                         $daemon{'ntp'} = 'chronyd';
                    671:                         $daemon{'mysql'} = 'mariadb';
                    672:                     } else {
                    673:                         $daemon{'ntp'} = 'ntpd';
                    674:                     }
1.35      raeburn   675:                 }
1.26      raeburn   676:             }
                    677:         }
1.6       raeburn   678:     } elsif ($distro =~ /^(?:debian|ubuntu)(\d+)/) {
                    679:         my $version = $1;
1.1       raeburn   680:         @runlevels = qw/2 3 4 5/;
                    681:         @norunlevels = qw/0 1 6/;
1.44      raeburn   682:         if (($distro =~ /^ubuntu/) && ($version <= 16)) {
                    683:             $checker_bin = '/usr/sbin/sysv-rc-conf';
                    684:         } else {
                    685:             $uses_systemctl{'ntp'} = 1;
                    686:             $uses_systemctl{'mysql'} = 1;
                    687:             $uses_systemctl{'apache'} = 1;
                    688:             $uses_systemctl{'memcached'} = 1;
                    689:             $uses_systemctl{'cups'} = 1;
                    690:         }
1.6       raeburn   691:         $daemon{'mysql'}  = 'mysql';
                    692:         $daemon{'apache'} = 'apache2';
                    693:         $daemon{'ntp'}    = 'ntp';
                    694:         if (($distro =~ /^ubuntu/) && ($version <= 8)) {
                    695:             $daemon{'cups'} = 'cupsys';
                    696:         }
1.45.2.19  raeburn   697:         if ((($distro =~ /^ubuntu/) && ($version >= 18)) ||
                    698:             (($distro  =~ /^debian/) && ($version >= 10))) {
1.45.2.6  raeburn   699:             $daemon{'ntp'}    = 'chrony';
                    700:         }
1.45.2.19  raeburn   701:         if (($distro  =~ /^debian/) && ($version >= 11)) {
                    702:             $daemon{'mysql'} = 'mariadb';
                    703:         }
1.26      raeburn   704:     } elsif ($distro =~ /^fedora(\d+)/) {
1.23      raeburn   705:         my $version = $1;
                    706:         if ($version >= 15) {
                    707:             $uses_systemctl{'ntp'} = 1;
                    708:         }
                    709:         if ($version >= 16) {
                    710:             $uses_systemctl{'mysql'} = 1;
                    711:             $uses_systemctl{'apache'} = 1;
1.35      raeburn   712:             $uses_systemctl{'memcached'} = 1;
                    713:             $uses_systemctl{'cups'} = 1;
1.23      raeburn   714:         }
1.39      raeburn   715:         if ($version >= 19) {
1.37      raeburn   716:             $daemon{'mysql'} = 'mariadb';
                    717:         }
1.45.2.5  raeburn   718:         if ($version >= 26) {
                    719:             $daemon{'ntp'} = 'chronyd';
                    720:         }
1.45.2.18  raeburn   721:     } elsif ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
1.29      raeburn   722:         my $version = $1;
                    723:         if ($version >= 7) {
                    724:             $uses_systemctl{'ntp'} = 1;
                    725:             $uses_systemctl{'mysql'} = 1;
                    726:             $uses_systemctl{'apache'} = 1;
1.35      raeburn   727:             $uses_systemctl{'memcached'} = 1;
                    728:             $uses_systemctl{'cups'} = 1;
1.30      raeburn   729:             $daemon{'mysql'} = 'mariadb';
1.29      raeburn   730:         }
1.45.2.3  raeburn   731:         if (($version >= 8) || ($distro eq 'oracle7')) {
                    732:             $daemon{'ntp'} = 'chronyd';
                    733:         }
1.1       raeburn   734:     }
1.23      raeburn   735:     my $nocheck;
1.1       raeburn   736:     if (! -x $checker_bin) {
1.23      raeburn   737:         if ($uses_systemctl{'mysql'} && $uses_systemctl{'apache'}) {
                    738:             if (! -x $sysctl_bin) {
                    739:                 $nocheck = 1;       
                    740:             }
                    741:         } else {
                    742:             $nocheck = 1;
                    743:         }
                    744:     }
                    745:     if ($nocheck) {
1.6       raeburn   746:         print &mt('Could not check runlevel status for MySQL or Apache')."\n";
1.1       raeburn   747:         return;
                    748:     }
                    749:     my $rlstr = join('',@runlevels);
                    750:     my $nrlstr = join('',@norunlevels);
1.23      raeburn   751: 
1.6       raeburn   752:     foreach my $type ('apache','mysql','ntp','cups','memcached') {
                    753:         my $service = $daemon{$type};
1.23      raeburn   754:         if ($uses_systemctl{$type}) {
1.35      raeburn   755:             if (($type eq 'memcached') || ($type eq 'cups')) {
                    756:                 if (-l "/etc/systemd/system/multi-user.target.wants/$service.service") {
                    757:                     $tostop{$type} = 1;
                    758:                 }
                    759:             } else {
                    760:                 if (!-l "/etc/systemd/system/multi-user.target.wants/$service.service") {
                    761:                     $needfix{$type} = "systemctl enable $service.service";
                    762:                 }
1.23      raeburn   763:             }
                    764:         } else {
                    765:             my $command = $checker_bin.' --list '.$service.' 2>/dev/null';
1.35      raeburn   766:             if ($type eq 'cups') {
1.23      raeburn   767:                 if ($distro =~ /^(?:debian|ubuntu)(\d+)/) {
                    768:                     my $version = $1;
                    769:                     if (($distro =~ /^ubuntu/) && ($version <= 8)) {
                    770:                         $command = $checker_bin.' --list cupsys 2>/dev/null';
1.19      raeburn   771:                     }
                    772:                 }
                    773:             }
1.23      raeburn   774:             my $results = `$command`;
                    775:             my $tofix;
                    776:             if ($results eq '') {
                    777:                 if (($type eq 'apache') || ($type eq 'mysql') || ($type eq 'ntp')) {
                    778:                     if ($distro  =~ /^(debian|ubuntu)/) {
                    779:                         $tofix = "update-rc.d $type defaults";
                    780:                     } else {
                    781:                         $tofix = "$checker_bin --add $service\n";
                    782:                     }
1.6       raeburn   783:                 }
1.23      raeburn   784:             } else {
                    785:                 my %curr_runlevels;
                    786:                 for (my $rl=0; $rl<=6; $rl++) {
                    787:                     if ($results =~ /$rl:on/) { $curr_runlevels{$rl}++; }
                    788:                 }
                    789:                 if (($type eq 'apache') || ($type eq 'mysql') || ($type eq 'ntp')) {
                    790:                     my $warning;
                    791:                     foreach my $rl (@runlevels) {
                    792:                         if (!exists($curr_runlevels{$rl})) {
                    793:                             $warning = 1;
                    794:                         }
                    795:                     }
                    796:                     if ($warning) {
                    797:                         $tofix = "$checker_bin --level $rlstr $service on\n";
                    798:                     }
                    799:                 } elsif (keys(%curr_runlevels) > 0) {
                    800:                     $tostop{$type} = 1;
1.1       raeburn   801:                 }
                    802:             }
1.23      raeburn   803:             if ($tofix) {
                    804:                 $needfix{$type} = $tofix;
1.1       raeburn   805:             }
1.5       raeburn   806:         }
1.1       raeburn   807:     }
                    808:     if ($distro =~ /^(suse|sles)([\d\.]+)$/) {
                    809:         my $name = $1;
                    810:         my $version = $2;
                    811:         my ($major,$minor);
                    812:         if ($name eq 'suse') {
                    813:             ($major,$minor) = split(/\./,$version);
                    814:         } else {
                    815:             $major = $version;
                    816:         }
1.45.2.1  raeburn   817:         if (($major > 10) && ($major <= 13)) {
1.8       raeburn   818:             if (&check_SuSEfirewall2_setup($instdir)) {
                    819:                 $needfix{'insserv'} = 1;
                    820:             }
1.1       raeburn   821:         }
                    822:     }
1.35      raeburn   823:     return (\%needfix,\%tostop,\%uses_systemctl);
1.1       raeburn   824: }
                    825: 
1.45.2.20  raeburn   826: sub check_systemd_security {
                    827:     my ($distro) = @_;
                    828:     my $service = 'httpd.service';
                    829:     if ($distro =~ /^(suse|sles|ubuntu|debian)/) {
                    830:         $service = 'apache2.service';
                    831:     }
                    832:     system("systemctl daemon-reload");
                    833:     if (open(PIPE,"systemctl show $service --property=ProtectHome 2>/dev/null |")) {
                    834:         my $protection = <PIPE>;
                    835:         close(PIPE);
                    836:         chomp($protection);
                    837:         if ($protection =~ /^ProtectHome=(read-only|yes)$/i) {
                    838:             return 1;
                    839:         }
                    840:     } else {
                    841:          print &mt('Could not check systemctl configuration for Apache')."\n";
                    842:     }
                    843:     return 0;
                    844: }
                    845: 
1.45.2.1  raeburn   846: sub uses_firewalld {
                    847:     my ($distro) = @_;
1.45.2.3  raeburn   848:     my ($inuse,$checkfirewalld,$zone);
1.45.2.1  raeburn   849:     if ($distro =~ /^(suse|sles)([\d\.]+)$/) {
                    850:         if (($1 eq 'sles') && ($2 >= 15)) {
                    851:             $checkfirewalld = 1;
                    852:         }
                    853:     } elsif ($distro =~ /^fedora(\d+)$/) {
                    854:         if ($1 >= 18) {
                    855:             $checkfirewalld = 1;
                    856:         }
1.45.2.18  raeburn   857:     } elsif ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
1.45.2.1  raeburn   858:         if ($1 >= 7) {
                    859:             $checkfirewalld = 1;
                    860:         }
                    861:     }
                    862:     if ($checkfirewalld) {
                    863:         my ($loaded,$active);
1.45.2.15  raeburn   864:         if (open(PIPE,"systemctl status firewalld 2>/dev/null |")) {
1.45.2.1  raeburn   865:             while (<PIPE>) {
                    866:                 chomp();
                    867:                 if (/^\s*Loaded:\s+(\w+)/) {
                    868:                     $loaded = $1;
                    869:                 }
1.45.2.15  raeburn   870:                 if (/^\s*Active:\s+(\w+)/) {
1.45.2.1  raeburn   871:                     $active = $1;
                    872:                 }
                    873:             }
                    874:             close(PIPE);
                    875:         }
                    876:         if (($loaded eq 'loaded') || ($active eq 'active')) {
                    877:             $inuse = 1;
1.45.2.3  raeburn   878:             my $cmd = 'firewall-cmd --get-default-zone';
                    879:             if (open(PIPE,"$cmd |")) {
                    880:                 my $result = <PIPE>;
                    881:                 chomp($result);
                    882:                 close(PIPE);
                    883:                 if ($result =~ /^\w+$/) {
                    884:                     $zone = $result;
                    885:                 }
                    886:             }
1.45.2.1  raeburn   887:         }
                    888:     }
1.45.2.3  raeburn   889:     return ($inuse,$zone);
1.45.2.1  raeburn   890: }
                    891: 
1.1       raeburn   892: sub chkfirewall {
1.5       raeburn   893:     my ($distro) = @_;
1.1       raeburn   894:     my $configfirewall = 1;
                    895:     my %ports = (
                    896:                     http  =>  80,
                    897:                     https => 443,
                    898:                 );
1.5       raeburn   899:     my %activefw;
1.45.2.3  raeburn   900:     my ($firewalld,$zone) = &uses_firewalld($distro);
                    901:     if ($firewalld) {
                    902:         my %current;
                    903:         if (open(PIPE,'firewall-cmd --permanent --zone='.$zone.' --list-services |')) {
                    904:             my $svc = <PIPE>;
                    905:             close(PIPE);
                    906:             chomp($svc);
                    907:             map { $current{$_} = 1; } (split(/\s+/,$svc));
                    908:         }
                    909:         if ($current{'http'} && $current{'https'}) {
                    910:             $configfirewall = 0;
                    911:         }
                    912:     } else {
                    913:         if (&firewall_is_active()) {
1.45.2.1  raeburn   914:             my $iptables = &get_pathto_iptables();
                    915:             if ($iptables eq '') {
                    916:                 print &mt('Firewall not checked as path to iptables not determined.')."\n";
                    917:             } else {
                    918:                 my @fwchains = &get_fw_chains($iptables,$distro);
                    919:                 if (@fwchains) {
                    920:                     foreach my $service ('http','https') {
                    921:                         foreach my $fwchain (@fwchains) {
                    922:                             if (&firewall_is_port_open($iptables,$fwchain,$ports{$service})) {
                    923:                                 $activefw{$service} = 1;
                    924:                                 last;
                    925:                             }
1.1       raeburn   926:                         }
                    927:                     }
1.45.2.1  raeburn   928:                     if ($activefw{'http'}) {
                    929:                         $configfirewall = 0;
                    930:                     }
                    931:                 } else {
                    932:                     print &mt('Firewall not checked as iptables Chains not identified.')."\n";
1.1       raeburn   933:                 }
                    934:             }
1.45.2.3  raeburn   935:         } else {
                    936:             print &mt('Firewall not enabled.')."\n";
1.1       raeburn   937:         }
                    938:     }
1.5       raeburn   939:     return ($configfirewall,\%activefw);
1.1       raeburn   940: }
                    941: 
                    942: sub chkapache {
                    943:     my ($distro,$instdir) = @_;
                    944:     my $fixapache = 1;
1.28      raeburn   945:     if ($distro =~ /^(debian|ubuntu)(\d+)$/) {
                    946:         my $distname = $1;
                    947:         my $version = $2;
1.33      raeburn   948:         my ($stdconf,$stdsite);
1.45.2.19  raeburn   949:         if ((($distname eq 'ubuntu') && ($version > 12)) ||
                    950:             (($distname eq 'debian') && ($version >= 10))) {
1.33      raeburn   951:             $stdconf = "$instdir/debian-ubuntu/ubuntu14/loncapa_conf";
                    952:             $stdsite = "$instdir/debian-ubuntu/ubuntu14/loncapa_sites";
                    953:         } else {
                    954:             $stdconf = "$instdir/debian-ubuntu/loncapa"; 
                    955:         }
                    956:         if (!-e $stdconf) {
1.1       raeburn   957:             $fixapache = 0;
                    958:             print &mt('Warning: No LON-CAPA Apache configuration file found for installation check.')."\n"; 
1.28      raeburn   959:         } else {
1.33      raeburn   960:             my ($configfile,$sitefile);
1.45.2.19  raeburn   961:             if ((($distname eq 'ubuntu') && ($version > 12)) ||
                    962:                 (($distname eq 'debian') && ($version >= 10))) {
1.45.2.10  raeburn   963:                 $sitefile = '/etc/apache2/sites-available/loncapa.conf';
                    964:                 $configfile = '/etc/apache2/conf-available/loncapa.conf';
1.33      raeburn   965:             } else {
1.45.2.10  raeburn   966:                 $configfile = '/etc/apache2/sites-available/loncapa';
1.28      raeburn   967:             }
1.33      raeburn   968:             if (($configfile ne '') && (-e $configfile) && (-e $stdconf))  {
                    969:                 if (open(PIPE, "diff --brief $stdconf $configfile |")) {
1.28      raeburn   970:                     my $diffres = <PIPE>;
                    971:                     close(PIPE);
                    972:                     chomp($diffres);
                    973:                     unless ($diffres) {
                    974:                         $fixapache = 0;
                    975:                     }
1.1       raeburn   976:                 }
                    977:             }
1.45.2.19  raeburn   978:             if ((!$fixapache) && ((($distname eq 'ubuntu') && ($version > 12)) ||
                    979:                                   (($distname eq 'debian') && ($version >= 10))))  {
1.33      raeburn   980:                 if (($sitefile ne '') && (-e $sitefile) && (-e $stdsite)) {
                    981:                     if (open(PIPE, "diff --brief $stdsite $sitefile |")) {
                    982:                         my $diffres = <PIPE>;
                    983:                         close(PIPE);
                    984:                         chomp($diffres);
1.45.2.20  raeburn   985:                         if ($diffres) {
                    986:                             $fixapache = 1;
                    987:                         } else {
1.33      raeburn   988:                             $fixapache = 0;
                    989:                         }
                    990:                     }
                    991:                 }
                    992:             }
1.1       raeburn   993:         }
1.6       raeburn   994:         if (!$fixapache) {
                    995:             foreach my $module ('headers.load','expires.load') {
                    996:                 unless (-l "/etc/apache2/mods-enabled/$module") {
                    997:                     $fixapache = 1;
                    998:                 }
                    999:             }
                   1000:         }
1.45.2.19  raeburn  1001:         if ((!$fixapache) && (($distname eq 'ubuntu') || ($distname eq 'debian'))) {
1.45.2.7  raeburn  1002:             my $sitestatus = "/etc/apache2/mods-available/status.conf";
                   1003:             my $stdstatus = "$instdir/debian-ubuntu/status.conf";
                   1004:             if ((-e $stdstatus) && (-e $sitestatus)) {
                   1005:                 if (open(PIPE, "diff --brief $stdstatus $sitestatus |")) {
                   1006:                     my $diffres = <PIPE>;
                   1007:                     close(PIPE);
                   1008:                     chomp($diffres);
                   1009:                     if ($diffres) {
                   1010:                         $fixapache = 1;
                   1011:                     }
                   1012:                 }
                   1013:             }
                   1014:         }
1.45.2.1  raeburn  1015:     } elsif ($distro =~ /^(suse|sles)([\d\.]+)$/) {
                   1016:         my ($name,$version) = ($1,$2);
1.1       raeburn  1017:         my $apache = 'apache';
1.45.2.1  raeburn  1018:         my $conf_file = "$instdir/sles-suse/default-server.conf";
                   1019:         if ($version >= 10) {
1.8       raeburn  1020:             $apache = 'apache2';
1.1       raeburn  1021:         }
1.45.2.1  raeburn  1022:         if (($name eq 'sles') && ($version >= 12)) {
                   1023:             $conf_file = "$instdir/sles-suse/apache2.4/default-server.conf";
                   1024:         }
                   1025:         if (!-e $conf_file) {
1.1       raeburn  1026:             $fixapache = 0;
                   1027:             print &mt('Warning: No LON-CAPA Apache configuration file found for installation check.')."\n";
1.45.2.1  raeburn  1028:         } elsif (-e "/etc/$apache/default-server.conf") {
                   1029:             if (open(PIPE, "diff --brief $conf_file /etc/$apache/default-server.conf |")) {
1.9       raeburn  1030:                 my $diffres = <PIPE>;
                   1031:                 close(PIPE);
                   1032:                 chomp($diffres);
                   1033:                 unless ($diffres) {
                   1034:                     $fixapache = 0;
                   1035:                 }
                   1036:             }
                   1037:         }
                   1038:     } elsif ($distro eq 'rhes4') {
                   1039:         if (!-e "$instdir/rhes4/httpd.conf") {
                   1040:             $fixapache = 0;
                   1041:             print &mt('Warning: No LON-CAPA Apache configuration file found for installation check.')."\n";
                   1042:         } elsif ((-e "/etc/httpd/conf/httpd.conf") && (-e "$instdir/rhes4/httpd.conf")) {
                   1043:             if (open(PIPE, "diff --brief $instdir/rhes4/httpd.conf /etc/httpd/conf/httpd.conf |")) {
1.1       raeburn  1044:                 my $diffres = <PIPE>;
                   1045:                 close(PIPE);
                   1046:                 chomp($diffres);
                   1047:                 unless ($diffres) {
                   1048:                     $fixapache = 0;
                   1049:                 }
                   1050:             }
                   1051:         }
                   1052:     } else {
1.14      raeburn  1053:         my $configfile = 'httpd.conf';
1.45.2.5  raeburn  1054:         my $mpmfile = 'mpm.conf';
1.45.2.18  raeburn  1055:         if ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
1.29      raeburn  1056:             if ($1 >= 7) {
                   1057:                 $configfile = 'apache2.4/httpd.conf';
                   1058:             } elsif ($1 > 5) {
1.14      raeburn  1059:                 $configfile = 'new/httpd.conf';
                   1060:             }
                   1061:         } elsif ($distro =~ /^fedora(\d+)$/) {
1.29      raeburn  1062:             if ($1 > 17) {
1.45.2.5  raeburn  1063:                 $configfile = 'apache2.4/httpd.conf';
1.29      raeburn  1064:             } elsif ($1 > 10) {
1.15      raeburn  1065:                 $configfile = 'new/httpd.conf';
1.14      raeburn  1066:             }
                   1067:         }
                   1068:         if (!-e "$instdir/centos-rhes-fedora-sl/$configfile") {
1.1       raeburn  1069:             $fixapache = 0;
                   1070:             print &mt('Warning: No LON-CAPA Apache configuration file found for installation check.')."\n";
1.14      raeburn  1071:         } elsif ((-e "/etc/httpd/conf/httpd.conf") && (-e "$instdir/centos-rhes-fedora-sl/$configfile")) {
                   1072:             if (open(PIPE, "diff --brief $instdir/centos-rhes-fedora-sl/$configfile /etc/httpd/conf/httpd.conf |")) {
1.1       raeburn  1073:                 my $diffres = <PIPE>;
                   1074:                 close(PIPE);
                   1075:                 chomp($diffres);
                   1076:                 unless ($diffres) {
                   1077:                     $fixapache = 0;
                   1078:                 }
                   1079:             }
                   1080:         }
1.45.2.5  raeburn  1081:         if (-e "/etc/httpd/conf.modules.d/00-mpm.conf") {
                   1082:             if (!-e "$instdir/centos-rhes-fedora-sl/$mpmfile") {
                   1083:                 print &mt('Warning: No LON-CAPA Apache MPM configuration file found for installation check.')."\n";
                   1084:             } elsif ((-e "/etc/httpd/conf.modules.d/00-mpm.conf") && (-e "$instdir/centos-rhes-fedora-sl/$mpmfile")) {
                   1085:                 if (open(PIPE, "diff --brief $instdir/centos-rhes-fedora-sl/$mpmfile /etc/httpd/conf.modules.d/00-mpm.conf |")) {
                   1086:                     my $diffres = <PIPE>;
                   1087:                     close(PIPE);
                   1088:                     chomp($diffres);
                   1089:                     if ($diffres) {
                   1090:                         $fixapache = 1;
                   1091:                     }
                   1092:                 }
                   1093:             }
                   1094:         }
1.1       raeburn  1095:     }
                   1096:     return $fixapache;
                   1097: }
                   1098: 
                   1099: sub chksrvcs {
                   1100:     my ($distro,$tostop) = @_;
                   1101:     my %stopsrvcs;
                   1102:     if (ref($tostop) eq 'HASH') {
                   1103:         %stopsrvcs = %{$tostop};
                   1104:     }
1.6       raeburn  1105:     foreach my $service ('cups','memcached') {
1.1       raeburn  1106:         next if (exists($stopsrvcs{$service}));
                   1107:         my $daemon = $service;
                   1108:         if ($service eq 'cups') {
                   1109:             $daemon = 'cupsd';
                   1110:         }
                   1111:         my $cmd = "ps -ef |grep '$daemon' |grep -v grep";
                   1112:         if (open(PIPE,'-|',$cmd)) {
                   1113:             my $daemonrunning = <PIPE>;
                   1114:             chomp($daemonrunning);
                   1115:             close(PIPE);
                   1116:             if ($daemonrunning) {
1.12      raeburn  1117:                 if ($service eq 'memcached') {
1.16      raeburn  1118:                     my $cmd = '/usr/bin/memcached';
                   1119:                     if ($distro =~ /^(suse|sles)/) {
                   1120:                         $cmd = '/usr/sbin/memcached';
                   1121:                     }
1.12      raeburn  1122:                     unless ($daemonrunning =~ m{^www[^/]+\Q$cmd -m 400 -v\E$}) {
1.10      raeburn  1123:                         $stopsrvcs{$service} = 1;
                   1124:                     }
                   1125:                 } else {
                   1126:                     $stopsrvcs{$service} = 1;
                   1127:                 }
1.1       raeburn  1128:             }
                   1129:         }
1.10      raeburn  1130:     }
1.1       raeburn  1131:     return \%stopsrvcs;
                   1132: }
                   1133: 
                   1134: sub need_download {
1.45.2.16  raeburn  1135:     my ($distro,$instdir) = @_;
1.1       raeburn  1136:     my $needs_download = 1;
                   1137:     my ($production,$testing,$stdsizes) = &download_versionslist();
1.45.2.16  raeburn  1138:     my ($localcurrent,$localtesting,%tarball,%localsize,%bymodtime,
1.1       raeburn  1139:         %bysize,$filetouse,$downloadstatus);
1.45.2.16  raeburn  1140:     if (opendir(my $dir,$instdir)) {
1.1       raeburn  1141:         my (@lcdownloads,$version);
                   1142:         foreach my $file (readdir($dir)) {
                   1143:             if ($file =~ /^loncapa\-([\w\-.]+)\.tar\.gz$/) {
                   1144:                 $version = $1;
                   1145:             } else {
                   1146:                 next;
                   1147:             }
                   1148:             if (ref($stdsizes) eq 'HASH') {
                   1149:                 if ($version eq 'current') {
1.45.2.16  raeburn  1150:                     my @stats = stat("$instdir/$file");
1.1       raeburn  1151:                     $localcurrent = $stats[7];
1.4       raeburn  1152:                     if ($localcurrent == $stdsizes->{$production}) {
1.1       raeburn  1153:                         $needs_download = 0;
                   1154:                         $filetouse = $file;
                   1155:                     }
                   1156:                 } elsif ($version eq 'testing') {
1.45.2.16  raeburn  1157:                     my @stats = stat("$instdir/$file");
1.1       raeburn  1158:                     $localtesting = $stats[7];
1.4       raeburn  1159:                     if ($localtesting == $stdsizes->{$testing}) {
1.1       raeburn  1160:                         $needs_download = 0;
                   1161:                         $filetouse = $file;
                   1162:                     }
                   1163:                 }
                   1164:             }
                   1165:             $tarball{$version} = $file;
                   1166:             push(@lcdownloads,$version);
                   1167:         }
                   1168:         if ($needs_download) {
                   1169:             if (@lcdownloads > 0) {
                   1170:                 foreach my $version (@lcdownloads) {
1.45.2.16  raeburn  1171:                     my @stats = stat("$instdir/$tarball{$version}");
1.1       raeburn  1172:                     my $mtime = $stats[9];
                   1173:                     $localsize{$version} = $stats[7];
                   1174:                     if ($mtime) {
                   1175:                         push(@{$bymodtime{$mtime}},$version);
                   1176:                     }
                   1177:                     if ($localsize{$version}) {
                   1178:                         push(@{$bysize{$localsize{$version}}},$version);
                   1179:                     }
                   1180:                 }
                   1181:                 if ($testing) {
                   1182:                     if (exists($localsize{$testing})) {
                   1183:                         if ($stdsizes->{$testing} == $localsize{$testing}) {
                   1184:                             $needs_download = 0;
                   1185:                             $filetouse = 'loncapa-'.$testing.'.tar.gz';
                   1186:                         }
                   1187:                     }
                   1188:                 }
                   1189:                 if ($needs_download) { 
                   1190:                     if ($production) {
                   1191:                         if (exists($localsize{$production})) {
                   1192:                             if ($stdsizes->{$production} == $localsize{$production}) {
                   1193:                                 $needs_download = 0;
                   1194:                                 $filetouse = 'loncapa-'.$production.'.tar.gz';
                   1195:                             }
                   1196:                         }
                   1197:                     }
                   1198:                 }
                   1199:                 if ($needs_download) {
                   1200:                     my @sorted = sort { $b <=> $a } keys(%bymodtime);
                   1201:                     my $newest = $sorted[0];
                   1202:                     if (ref($bymodtime{$newest}) eq 'ARRAY') {
                   1203:                         $downloadstatus = 
1.45.2.16  raeburn  1204:                               "Latest LON-CAPA source download in $instdir is: ".
1.1       raeburn  1205:                               join(',',@{$bymodtime{$newest}})." (downloaded ".
                   1206:                               localtime($newest).")\n";
                   1207:                     }
                   1208:                 } else {
                   1209:                     $downloadstatus = 
1.45.2.16  raeburn  1210:                         "The $instdir directory already contains the latest LON-CAPA version:".
1.1       raeburn  1211:                         "\n".$filetouse."\n"."which can be used for installation.\n";
                   1212:                 }
                   1213:             } else {
1.45.2.16  raeburn  1214:                 $downloadstatus = "The $instdir directory does not appear to contain any downloaded LON-CAPA source code files which can be used for installation.\n";
1.1       raeburn  1215:             }
                   1216:         }
                   1217:     } else {
1.45.2.16  raeburn  1218:         $downloadstatus = "Could not open $instdir directory to look for existing downloads of LON-CAPA source code.\n";
1.1       raeburn  1219:     }
                   1220:     return ($needs_download,$downloadstatus,$filetouse,$production,$testing);
                   1221: }
                   1222: 
                   1223: sub check_mysql_setup {
1.45.2.12  raeburn  1224:     my ($instdir,$dsn,$distro) = @_;
                   1225:     my ($mysqlsetup,$has_pass,$mysql_unix_socket,$mysql_has_wwwuser);
1.1       raeburn  1226:     my $dbh = DBI->connect($dsn,'root','',{'PrintError'=>0});
1.45.2.19  raeburn  1227:     my ($mysqlversion,$mysqlminorversion,$mysqlsubver,$mysqlname) = &get_mysql_version();
                   1228:     if (($mysqlname =~ /^MariaDB/i) && (($mysqlversion == 10 && $mysqlminorversion >= 4) || ($mysqlversion >= 11))) {
1.45.2.9  raeburn  1229:         if ($dbh) {
                   1230:             my $sth = $dbh->prepare("SELECT Priv FROM mysql.global_priv WHERE (User = 'root' AND Host ='localhost')");
                   1231:             $sth->execute();
                   1232:             while (my $priv = $sth->fetchrow_array) {
1.45.2.14  raeburn  1233:                 if ($priv =~ /unix_socket/) {
1.45.2.9  raeburn  1234:                     $mysql_unix_socket = 1;
                   1235:                     last;
                   1236:                 }
                   1237:             }
                   1238:             $sth->finish();
                   1239:             if ($mysql_unix_socket) {
                   1240:                 print_and_log(&mt('MariaDB using unix_socket for root access from localhost.')."\n");
                   1241:                 $mysqlsetup = 'rootok';
1.45.2.12  raeburn  1242:                 $mysql_has_wwwuser = &check_mysql_wwwuser($dbh);
1.45.2.9  raeburn  1243:                 return ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser,$mysql_unix_socket);
                   1244:             }
                   1245:         }
                   1246:     }
1.1       raeburn  1247:     if ($dbh) {
1.45.2.12  raeburn  1248:         $mysqlsetup = 'noroot';
1.45.2.19  raeburn  1249:         if (($mysqlname !~ /^MariaDB/i) && (($mysqlversion == 5 && $mysqlminorversion >= 7) || ($mysqlversion >= 6))) {
1.45.2.12  raeburn  1250:             my $sth = $dbh->prepare("SELECT plugin from mysql.user where User='root'");
                   1251:             $sth->execute();
                   1252:             while (my $priv = $sth->fetchrow_array) {
                   1253:                 if ($priv =~ /auth_socket/) {
                   1254:                     $mysql_unix_socket = 1;
                   1255:                     last;
                   1256:                 }
                   1257:             }
                   1258:             $sth->finish();
                   1259:             if ($mysql_unix_socket) {
                   1260:                 print_and_log(&mt('MySQL using unix_socket for root access from localhost.')."\n");
                   1261:                 $mysqlsetup = 'rootok';
                   1262:                 $mysql_has_wwwuser = &check_mysql_wwwuser($dbh);
                   1263:                 return ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser,$mysql_unix_socket);
                   1264:             }
1.45.2.14  raeburn  1265:         }
1.1       raeburn  1266:     } elsif ($DBI::err =~ /1045/) {
                   1267:         $has_pass = 1;
1.34      raeburn  1268:     } elsif ($distro =~ /^ubuntu(\d+)$/) {
                   1269:         my $version = $1;
                   1270:         if ($1 > 12) {
                   1271:             print_and_log(&mt('Restarting mysql, please be patient')."\n");
                   1272:             if (open (PIPE, "service mysql restart 2>&1 |")) {
                   1273:                 while (<PIPE>) {
                   1274:                     print $_;
                   1275:                 }
                   1276:                 close(PIPE);
                   1277:             }
                   1278:             $dbh = DBI->connect($dsn,'root','',{'PrintError'=>0});
                   1279:             if ($dbh) {
                   1280:                 $mysqlsetup = 'noroot';
1.45.2.12  raeburn  1281:                 $mysql_has_wwwuser = &check_mysql_wwwuser($dbh);
1.34      raeburn  1282:             } elsif ($DBI::err =~ /1045/) {
                   1283:                 $has_pass = 1;
                   1284:             } else {
                   1285:                 $mysqlsetup = 'needsrestart';
1.45.2.16  raeburn  1286:                 $mysql_has_wwwuser = &check_mysql_wwwuser();
1.34      raeburn  1287:                 return ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser);
                   1288:             }
                   1289:         }
1.1       raeburn  1290:     }
                   1291:     if ($has_pass) {
                   1292:         print &mt('You have already set a root password for the MySQL database.')."\n";
                   1293:         my $currpass = &get_mysql_password(&mt('Please enter the password now'));
                   1294:         $dbh = DBI->connect($dsn,'root',$currpass,{'PrintError'=>0});
                   1295:         if ($dbh) {
                   1296:             $mysqlsetup = 'rootok';
                   1297:             print_and_log(&mt('Password accepted.')."\n");
1.45.2.12  raeburn  1298:             $mysql_has_wwwuser = &check_mysql_wwwuser($dbh);
1.1       raeburn  1299:         } else {
                   1300:             $mysqlsetup = 'rootfail';
                   1301:             print_and_log(&mt('Problem accessing MySQL.')."\n");
                   1302:             if ($DBI::err =~ /1045/) {
                   1303:                 print_and_log(&mt('Perhaps the password was incorrect?')."\n");
                   1304:                 print &mt('Try again?').' ';
                   1305:                 $currpass = &get_mysql_password(&mt('Re-enter password now')); 
                   1306:                 $dbh = DBI->connect($dsn,'root',$currpass,{'PrintError'=>0});
                   1307:                 if ($dbh) {
                   1308:                     $mysqlsetup = 'rootok';
                   1309:                     print_and_log(&mt('Password accepted.')."\n");
1.45.2.12  raeburn  1310:                     $mysql_has_wwwuser = &check_mysql_wwwuser($dbh);
1.1       raeburn  1311:                 } else {
                   1312:                     if ($DBI::err =~ /1045/) {
                   1313:                         print_and_log(&mt('Incorrect password.')."\n");
                   1314:                     }
1.45.2.16  raeburn  1315:                     $mysql_has_wwwuser = &check_mysql_wwwuser();
1.1       raeburn  1316:                 }
                   1317:             }
                   1318:         }
1.34      raeburn  1319:     } elsif ($mysqlsetup ne 'noroot') {
1.1       raeburn  1320:         print_and_log(&mt('Problem accessing MySQL.')."\n");
                   1321:         $mysqlsetup = 'rootfail';
1.45.2.16  raeburn  1322:         $mysql_has_wwwuser = &check_mysql_wwwuser();
1.1       raeburn  1323:     }
1.34      raeburn  1324:     return ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser);
1.1       raeburn  1325: }
                   1326: 
                   1327: sub check_mysql_wwwuser {
1.45.2.12  raeburn  1328:     my ($dbh) = @_;
1.1       raeburn  1329:     my $mysql_wwwuser;
1.45.2.12  raeburn  1330:     if ($dbh) {
                   1331:         $mysql_wwwuser = $dbh->selectrow_array("SELECT COUNT(User) FROM mysql.user WHERE (User = 'www' AND Host ='localhost')");
                   1332:     } else {
                   1333:         my $dbhn = DBI->connect("DBI:mysql:database=information_schema",'www','localhostkey',
                   1334:                                 {PrintError => +0}) || return;
                   1335:         if ($dbhn) {
                   1336:             $mysql_wwwuser = 1;
                   1337:             $dbhn->disconnect;
                   1338:         }
1.1       raeburn  1339:     }
                   1340:     return $mysql_wwwuser;
                   1341: }
                   1342: 
                   1343: sub check_loncapa_mysqldb {
                   1344:     my ($dbh) = @_;
                   1345:     my $has_lcdb;
                   1346:     if (ref($dbh)) {
                   1347:         my $sth = $dbh->prepare("SHOW DATABASES");
                   1348:         $sth->execute();
                   1349:         while (my $dbname = $sth->fetchrow_array) {
                   1350:             if ($dbname eq 'loncapa') {
                   1351:                 $has_lcdb = 1;
                   1352:                 last;
                   1353:             }
                   1354:         }
                   1355:         $sth->finish();
                   1356:     }
                   1357:     return $has_lcdb;
                   1358: }
                   1359: 
                   1360: sub get_pathto_iptables {
                   1361:     my $iptables;
                   1362:     if (-e '/sbin/iptables') {
                   1363:         $iptables = '/sbin/iptables';
                   1364:     } elsif (-e '/usr/sbin/iptables') {
                   1365:         $iptables = '/usr/sbin/iptables';
                   1366:     } else {
                   1367:         print &mt('Unable to find iptables command.')."\n";
                   1368:     }
                   1369:     return $iptables;
                   1370: }
                   1371: 
                   1372: sub firewall_is_active {
                   1373:     if (-e '/proc/net/ip_tables_names') {
1.45.2.19  raeburn  1374:         my $status;
1.45.2.1  raeburn  1375:         if (open(PIPE,'cat /proc/net/ip_tables_names |grep filter |')) {
1.45.2.19  raeburn  1376:             $status = <PIPE>;
1.45.2.1  raeburn  1377:             close(PIPE);
                   1378:             chomp($status);
                   1379:             if ($status eq 'filter') {
                   1380:                 return 1;
                   1381:             }
                   1382:         }
1.45.2.19  raeburn  1383:         unless ($status) {
                   1384:             if (open(PIPE,'nft list tables |')) {
                   1385:                 while(<PIPE>) {
                   1386:                     chomp();
                   1387:                     if (/filter$/) {
                   1388:                         $status = 1;
                   1389:                         last;
                   1390:                     }
                   1391:                 }
                   1392:                 close(PIPE);
                   1393:                 if ($status) {
                   1394:                     return 1;
                   1395:                 }
                   1396:             }
                   1397:         }
1.1       raeburn  1398:     }
1.45.2.1  raeburn  1399:     return 0;
1.1       raeburn  1400: }
                   1401: 
                   1402: sub get_fw_chains {
1.5       raeburn  1403:     my ($iptables,$distro) = @_;
1.1       raeburn  1404:     my @fw_chains;
                   1405:     my $suse_config = "/etc/sysconfig/SuSEfirewall2";
                   1406:     my $ubuntu_config = "/etc/ufw/ufw.conf";
                   1407:     if (-e $suse_config) {
                   1408:         push(@fw_chains,'input_ext');
                   1409:     } else {
                   1410:         my @posschains;
                   1411:         if (-e $ubuntu_config) {
                   1412:             @posschains = ('ufw-user-input','INPUT');
1.5       raeburn  1413:         } elsif ($distro =~ /^debian5/) {
                   1414:             @posschains = ('INPUT');
1.45.2.1  raeburn  1415:         } elsif ($distro =~ /^(suse|sles)(\d+)/) {
                   1416:             @posschains = ('IN_public');
1.1       raeburn  1417:         } else {
                   1418:             @posschains = ('RH-Firewall-1-INPUT','INPUT');
                   1419:             if (!-e '/etc/sysconfig/iptables') {
                   1420:                 if (!-e '/var/lib/iptables') {
                   1421:                     print &mt('Unable to find iptables file containing static definitions.')."\n";
                   1422:                 }
                   1423:                 push(@fw_chains,'RH-Firewall-1-INPUT');
                   1424:             }
                   1425:         }
                   1426:         if ($iptables eq '') {
                   1427:             $iptables = &get_pathto_iptables();
                   1428:         }
                   1429:         my %counts;
                   1430:         if (open(PIPE,"$iptables -L -n |")) {
                   1431:             while(<PIPE>) {
                   1432:                 foreach my $chain (@posschains) {
                   1433:                     if (/(\Q$chain\E)/) {
                   1434:                         $counts{$1} ++;
                   1435:                     }
                   1436:                 }
                   1437:             }
                   1438:             close(PIPE);
                   1439:         }
                   1440:         foreach my $fw_chain (@posschains) {
                   1441:             if ($counts{$fw_chain}) {
                   1442:                 unless(grep(/^\Q$fw_chain\E$/,@fw_chains)) {
                   1443:                     push(@fw_chains,$fw_chain);
                   1444:                 }
                   1445:             }
                   1446:         }
                   1447:     }
                   1448:     return @fw_chains;
                   1449: }
                   1450: 
                   1451: sub firewall_is_port_open {
                   1452:     my ($iptables,$fw_chain,$port) = @_;
                   1453:     # returns 1 if the firewall port is open, 0 if not.
                   1454:     #
                   1455:     # check if firewall is active or installed
                   1456:     return if (! &firewall_is_active());
                   1457:     my $count = 0;
                   1458:     if (open(PIPE,"$iptables -L $fw_chain -n |")) {
                   1459:         while(<PIPE>) {
                   1460:             if (/tcp dpt\:\Q$port\E/) {
                   1461:                 $count ++;
                   1462:                 last;
                   1463:             }
                   1464:         }
                   1465:         close(PIPE);
                   1466:     } else {
                   1467:         print &mt('Firewall status not checked: unable to run [_1].','iptables -L')."\n";
                   1468:     }
                   1469:     return $count;
                   1470: }
                   1471: 
                   1472: sub get_mysql_password {
                   1473:     my ($prompt) = @_;
                   1474:     local $| = 1;
                   1475:     print $prompt.': ';
                   1476:     my $newpasswd = '';
                   1477:     ReadMode 'raw';
                   1478:     my $key;
                   1479:     while(ord($key = ReadKey(0)) != 10) {
                   1480:         if(ord($key) == 127 || ord($key) == 8) {
                   1481:             chop($newpasswd);
                   1482:             print "\b \b";
                   1483:         } elsif(!ord($key) < 32) {
                   1484:             $newpasswd .= $key;
                   1485:             print '*';
                   1486:         }
                   1487:     }
                   1488:     ReadMode 'normal';
                   1489:     print "\n";
                   1490:     return $newpasswd;
                   1491: }
                   1492: 
                   1493: sub check_SuSEfirewall2_setup {
                   1494:     my ($instdir) = @_;
                   1495:     my $need_override = 1;
1.9       raeburn  1496:     if ((-e "/etc/insserv/overrides/SuSEfirewall2_setup") && (-e "$instdir/sles-suse/SuSEfirewall2_setup")) {
                   1497:         if (open(PIPE, "diff --brief $instdir/sles-suse/SuSEfirewall2_setup /etc/insserv/overrides/SuSEfirewall2_setup  |")) {
1.1       raeburn  1498:             my $diffres = <PIPE>;
                   1499:             close(PIPE);
                   1500:             chomp($diffres);
                   1501:             unless ($diffres) {
                   1502:                 $need_override = 0;
                   1503:             }
                   1504:         }
                   1505:     }
                   1506:     return $need_override;
                   1507: }
                   1508: 
                   1509: sub download_versionslist {
                   1510:     my ($production,$testing,%sizes);
                   1511:     if (-e "latest.txt") {
                   1512:          unlink("latest.txt");
                   1513:     }
                   1514:     my $rtncode = system("wget http://install.loncapa.org/versions/latest.txt ".
                   1515:                          "> /dev/null 2>&1");
                   1516:     if (!$rtncode) {
                   1517:         if (open(my $fh,"<latest.txt")) {
                   1518:             my @info = <$fh>;
                   1519:             close($fh);
                   1520:             foreach my $line (@info) {
                   1521:                 chomp();
                   1522:                 if ($line =~ /^\QLATEST-IS: \E([\w\-.]+):(\d+)$/) {
                   1523:                      $production = $1;
                   1524:                      $sizes{$1} = $2;
                   1525:                 } elsif ($line =~ /^LATEST-TESTING-IS: \E([\w\-.]+):(\d+)$/) {
                   1526:                      $testing = $1;
                   1527:                      $sizes{$1} = $2;
                   1528:                 }
                   1529:             }
                   1530:         }
                   1531:     }
                   1532:     return ($production,$testing,\%sizes);
                   1533: }
                   1534: 
                   1535: #
                   1536: # End helper routines.
                   1537: # Main script starts here
                   1538: #
                   1539: 
                   1540: print "
                   1541: ********************************************************************
                   1542: 
                   1543:                     ".&mt('Welcome to LON-CAPA')."
                   1544: 
                   1545: ".&mt('This script will configure your system for installation of LON-CAPA.')."
                   1546: 
                   1547: ********************************************************************
                   1548: 
                   1549: ".&mt('The following actions are available:')."
                   1550: 
1.4       raeburn  1551: ".&mt('1.')." ".&mt('Create the www user/group.')."
1.1       raeburn  1552:    ".&mt('This is the user/group ownership under which Apache child processes run.')."
                   1553:    ".&mt('It also owns most directories within the /home/httpd directory.')." 
                   1554:    ".&mt('This directory is where most LON-CAPA files and directories are stored.')."
1.4       raeburn  1555: ".&mt('2.')." ".&mt('Install the package LON-CAPA uses to authenticate users.')."
                   1556: ".&mt('3.')." ".&mt('Set-up the MySQL database.')."
                   1557: ".&mt('4.')." ".&mt('Set-up MySQL permissions.')."
                   1558: ".&mt('5.')." ".&mt('Configure Apache web server.')."
1.45.2.20  raeburn  1559: ".&mt('6.')." ".&mt('Configure systemd security settings for Apache web server.')."
                   1560: ".&mt('7.')." ".&mt('Configure start-up of services.')."
                   1561: ".&mt('8.')." ".&mt('Check firewall settings.')."
                   1562: ".&mt('9.')." ".&mt('Stop services not used by LON-CAPA,')."
1.1       raeburn  1563:    ".&mt('i.e., services for a print server: [_1] daemon.',"'cups'")."
1.45.2.20  raeburn  1564: ".&mt('10.')." ".&mt('Download LON-CAPA source code in readiness for installation.')."
1.1       raeburn  1565: 
                   1566: ".&mt('Typically, you will run this script only once, when you first install LON-CAPA.')." 
                   1567: 
                   1568: ".&mt('The script will analyze your system to determine which actions are recommended.')."
                   1569: ".&mt('The script will then prompt you to choose the actions you would like taken.')."
                   1570: 
                   1571: ".&mt('For each the recommended action will be selected if you hit Enter/Return.')."
                   1572: ".&mt('To override the default, type the lower case option from the two options listed.')."
                   1573: ".&mt('So, if the default is "yes", ~[Y/n~] will be shown -- type n to override.')."
                   1574: ".&mt('Whereas if the default is "no", ~[y/N~] will be shown -- type y to override.')." 
                   1575: 
                   1576: ".&mt('To accept the default, simply hit Enter/Return on your keyboard.')."
                   1577: ".&mt('Otherwise type: y or n then hit the Enter/Return key.')."
                   1578: 
                   1579: ".&mt('Once a choice has been entered for all nine actions, required changes will be made.')."
                   1580: ".&mt('Feedback will be displayed on screen, and also stored in: [_1].','loncapa_install.log')."
                   1581: 
                   1582: ".&mt('Continue? ~[Y/n~] ');
                   1583: 
                   1584: my $go_on = &get_user_selection(1);
                   1585: if (!$go_on) {
                   1586:     exit;
                   1587: }
                   1588: 
                   1589: my $instdir = `pwd`;
                   1590: chomp($instdir);
                   1591: 
                   1592: my %callsub;
1.45.2.20  raeburn  1593: my @actions = ('wwwuser','pwauth','mysql','mysqlperms','apache','systemd',
1.1       raeburn  1594:                'runlevels','firewall','stopsrvcs','download');
                   1595: my %prompts = &texthash( 
                   1596:     wwwuser    => "Create the 'www' user?",
                   1597:     pwauth     => 'Install the package LON-CAPA uses to authenticate users?',
                   1598:     mysql      => 'Set-up the MySQL database?',
                   1599:     mysqlperms => 'Set-up MySQL permissions?',
                   1600:     apache     => 'Configure Apache web server?',
1.45.2.20  raeburn  1601:     systemd    => 'Configure systemd security settings for Apache web server?',
1.1       raeburn  1602:     runlevels  => 'Set overrides for start-up order of services?',
                   1603:     firewall   => 'Configure firewall settings for Apache',
                   1604:     stopsrvcs  => 'Stop extra services not required on a LON-CAPA server?',
                   1605:     download   => 'Download LON-CAPA source code in readiness for installation?',
                   1606: );
                   1607: 
                   1608: print "\n".&mt('Checking system status ...')."\n";
                   1609: 
                   1610: my $dsn = "DBI:mysql:database=mysql";
1.34      raeburn  1611: my ($distro,$gotprereqs,$localecmd,$packagecmd,$updatecmd,$installnow,$mysqlrestart,
1.45.2.9  raeburn  1612:     $recommended,$dbh,$has_pass,$mysql_unix_socket,$has_lcdb,$downloadstatus,
                   1613:     $filetouse,$production,$testing,$apachefw,$uses_systemctl) = &check_required($instdir,$dsn);
1.1       raeburn  1614: if ($distro eq '') {
                   1615:     print "\n".&mt('Linux distribution could not be verified as a supported distribution.')."\n".
                   1616:           &mt('The following are supported: [_1].',
                   1617:               'CentOS, RedHat Enterprise, Fedora, Scientific Linux, '.
1.45.2.3  raeburn  1618:               'Oracle Linux, openSuSE, SLES, Ubuntu LTS, Debian')."\n\n".
1.1       raeburn  1619:           &mt('Stopping execution.')."\n";
                   1620:     exit;
                   1621: }
1.34      raeburn  1622: if ($mysqlrestart) {
                   1623:     print "\n".&mt('The mysql daemon needs to be restarted using the following command:')."\n".
                   1624:           $mysqlrestart."\n\n".
                   1625:           &mt('Stopping execution of install.pl script.')."\n".
                   1626:           &mt('Please run the install.pl script again, once you have restarted mysql.')."\n";
                   1627:     exit;
                   1628: }
1.6       raeburn  1629: if ($localecmd ne '') {
                   1630:     print "\n".&mt('Although the LON-CAPA application itself is localized for a number of different languages, the default locale language for the Linux OS on which it runs should be US English.')."\n";
                   1631:     print "\n".&mt('Run the following command from the command line to set the default language for your OS, and then run this LON-CAPA installation set-up script again.')."\n\n".
                   1632:     $localecmd."\n\n".
                   1633:     &mt('Stopping execution.')."\n";
                   1634:     exit;
                   1635: }
1.1       raeburn  1636: if (!$gotprereqs) {
1.12      raeburn  1637:     print "\n".&mt('The LONCAPA-prerequisites package is not installed.')."\n".
1.1       raeburn  1638:           &mt('The following command can be used to install the package (and dependencies):')."\n\n".
                   1639:           $updatecmd."\n\n";
                   1640:     if ($installnow eq '') {
                   1641:         print &mt('Stopping execution.')."\n";
                   1642:         exit;
                   1643:     } else {
                   1644:         print &mt('Run command? ~[Y/n~]');
                   1645:         my $install_prereq = &get_user_selection(1);
                   1646:         if ($install_prereq) {
                   1647:             if (open(PIPE,'|-',$installnow)) {
                   1648:                 close(PIPE);
                   1649:                 $gotprereqs = &check_prerequisites($packagecmd,$distro);
                   1650:                 if (!$gotprereqs) {
1.12      raeburn  1651:                     print &mt('The LONCAPA-prerequisites package is not installed.')."\n".
1.1       raeburn  1652:                           &mt('Stopping execution.')."\n";
                   1653:                     exit;
                   1654:                 } else {
1.6       raeburn  1655:                     ($distro,$gotprereqs,$localecmd,$packagecmd,$updatecmd,$installnow,
1.45.2.9  raeburn  1656:                      $mysqlrestart,$recommended,$dbh,$has_pass,$mysql_unix_socket,
                   1657:                      $has_lcdb,$downloadstatus,$filetouse,$production,$testing,$apachefw,
                   1658:                      $uses_systemctl) = &check_required($instdir,$dsn);
1.1       raeburn  1659:                 }
                   1660:             } else {
1.12      raeburn  1661:                 print &mt('Failed to run command to install LONCAPA-prerequisites')."\n";
1.1       raeburn  1662:                 exit;
                   1663:             }
                   1664:         } else {
                   1665:             print &mt('Stopping execution.')."\n";
                   1666:             exit;
                   1667:         }
                   1668:     }
                   1669: }
                   1670: unless (ref($recommended) eq 'HASH') {
                   1671:     print "\n".&mt('An error occurred determining which actions are recommended.')."\n\n".
                   1672:           &mt('Stopping execution.')."\n";
                   1673:     exit;
                   1674: }
                   1675: 
                   1676: print "\n";
                   1677: my $num = 0;
                   1678: foreach my $action (@actions) {
                   1679:     $num ++;
                   1680:     my ($yesno,$defaultrun);
                   1681:     if (ref($recommended) eq 'HASH') {
1.4       raeburn  1682:         if (($action eq 'runlevels') || ($action eq 'stopsrvcs')) {
1.1       raeburn  1683:             $yesno = '[y/N]';
                   1684:             if (ref($recommended->{$action}) eq 'HASH') {
                   1685:                 if (keys(%{$recommended->{$action}}) > 0) {
                   1686:                     $yesno = &mt('~[Y/n~]');
                   1687:                     $defaultrun = 1;
                   1688:                 }
                   1689:             }
                   1690:         } else {
                   1691:             if ($action eq 'download') {
                   1692:                 if ($downloadstatus) {
                   1693:                     print "\n$downloadstatus\n";
                   1694:                 }
                   1695:             }
                   1696:             if ($recommended->{$action}) {
                   1697:                 $yesno = mt('~[Y/n~]');
                   1698:                 $defaultrun = 1;
                   1699:             } else {
                   1700:                 $yesno = &mt('~[y/N~]');
                   1701:             }
                   1702:         }
                   1703:         print $num.'. '.$prompts{$action}." $yesno ";
                   1704:         $callsub{$action} = &get_user_selection($defaultrun);
                   1705:     }
                   1706: }
                   1707: 
                   1708: my $lctarball = 'loncapa-current.tar.gz';
                   1709: my $sourcetarball = $lctarball;
                   1710: if ($callsub{'download'}) {
                   1711:     my ($production,$testing,$sizes) = &download_versionslist();
1.45.2.16  raeburn  1712:     my $homedir = '/root';
                   1713:     if ($distro =~ /^ubuntu/) {
                   1714:         if ($instdir ne $homedir) {
                   1715:             ($homedir) = ($instdir =~ m{^(.*)/[^/]+$});
                   1716:         }
                   1717:     }
1.1       raeburn  1718:     if ($production && $testing) {
                   1719:         if ($production ne $testing) {
                   1720:             print &mt('Two recent LON-CAPA releases are available: ')."\n".
1.3       raeburn  1721:                   &mt('1.').' '.&mt('A production release - version: [_1].',$production)."\n".
                   1722:                   &mt('2.').' '.&mt('A testing release - version: [_1].',$testing)."\n\n".
1.45.2.16  raeburn  1723:                   &mt("After download, the tar.gz file will be extracted into $homedir")."\n\n".
                   1724:                   &mt("Download the production release into $instdir? ~[Y/n~]");
1.1       raeburn  1725:             if (&get_user_selection(1)) {
1.4       raeburn  1726:                 $sourcetarball = 'loncapa-'.$production.'.tar.gz';
1.45.2.16  raeburn  1727:                 print "$sourcetarball will be downloaded into $instdir\n";
1.1       raeburn  1728:             } else {
                   1729:                 print "\n".&mt('Download the testing release? ~[Y/n~]');
                   1730:                 if (&get_user_selection(1)) {
1.4       raeburn  1731:                     $sourcetarball = 'loncapa-'.$testing.'.tar.gz';
1.45.2.16  raeburn  1732:                     print "$sourcetarball will be downloaded into $instdir\n";
                   1733:                 } else {
                   1734:                     $callsub{'download'} = 0;
1.1       raeburn  1735:                 }
                   1736:             }
                   1737:         }
                   1738:     } elsif ($production) {
                   1739:         print &mt('The most recent LON-CAPA release is version: [_1].',$production)."\n".
1.45.2.16  raeburn  1740:               &mt("After download, the tar.gz file will be extracted into $homedir")."\n\n".
                   1741:               &mt("Download the production release into $instdir? ~[Y/n~]");
1.1       raeburn  1742:         if (&get_user_selection(1)) {
1.20      raeburn  1743:             $sourcetarball = 'loncapa-'.$production.'.tar.gz';
1.45.2.16  raeburn  1744:             print "$sourcetarball will be downloaded into $instdir\n";
                   1745:         } else {
                   1746:             $callsub{'download'} = 0;
1.1       raeburn  1747:         }
                   1748:     }
                   1749: } elsif ($filetouse ne '') {
                   1750:     $sourcetarball = $filetouse;
                   1751: }
                   1752: 
                   1753: print_and_log("\n");
                   1754: 
                   1755: # Each action: report if skipping, or perform action and provide feedback. 
                   1756: if ($callsub{'wwwuser'}) {
                   1757:     &setup_www();
                   1758: } else {
                   1759:     &print_and_log(&mt('Skipping creation of user [_1].',"'www'")."\n");
                   1760: }
                   1761: 
                   1762: if ($callsub{'pwauth'}) {
1.4       raeburn  1763:     &build_and_install_mod_auth_external($instdir);
1.1       raeburn  1764: } else {
                   1765:     &print_and_log(&mt('Skipping [_1] installation.',"'pwauth'")."\n");
                   1766: }
                   1767: 
                   1768: if ($callsub{'mysql'}) {
                   1769:     if ($dbh) {
1.45.2.9  raeburn  1770:         &setup_mysql($callsub{'mysqlperms'},$dbh,$has_pass,
1.45.2.15  raeburn  1771:                      $mysql_unix_socket,$has_lcdb,$distro);
1.1       raeburn  1772:     } else {
                   1773:         print &mt('Unable to configure MySQL because access is denied.')."\n";
                   1774:     }
                   1775: } else {
                   1776:     &print_and_log(&mt('Skipping configuration of MySQL.')."\n");
                   1777:     if ($callsub{'mysqlperms'}) {
                   1778:         if ($dbh) {
1.45.2.9  raeburn  1779:             &setup_mysql_permissions($dbh,$has_pass,$mysql_unix_socket);
1.1       raeburn  1780:         } else {
                   1781:             print &mt('Unable to configure MySQL because access is denied.')."\n";  
                   1782:         }
                   1783:     } else {
                   1784:         &print_and_log(&mt('Skipping MySQL permissions setup.')."\n");
                   1785:     }
                   1786: }
                   1787: 
                   1788: if ($dbh) {
                   1789:     if (!$dbh->disconnect) {
                   1790:         &print_and_log(&mt('Failed to disconnect from MySQL:')."\n".
                   1791:                        $dbh->errstr);
                   1792:     }
                   1793: }
                   1794: 
                   1795: if ($callsub{'apache'}) {
                   1796:     if ($distro =~ /^(suse|sles)/) {
1.45.2.1  raeburn  1797:         &copy_apache2_suseconf($instdir,$distro);
1.1       raeburn  1798:     } elsif ($distro =~ /^(debian|ubuntu)/) {
1.28      raeburn  1799:         &copy_apache2_debconf($instdir,$distro);
1.1       raeburn  1800:     } else {
1.14      raeburn  1801:         &copy_httpd_conf($instdir,$distro);
1.45.2.5  raeburn  1802:         &copy_mpm_conf($instdir,$distro);
1.1       raeburn  1803:     }
                   1804: } else {
                   1805:     print_and_log(&mt('Skipping configuration of Apache web server.')."\n");
                   1806: }
                   1807: 
1.45.2.20  raeburn  1808: if ($callsub{'systemd'}) {
                   1809:     &check_systemd_update($distro);
                   1810: } else {
                   1811:     print_and_log('Skipping systemd configuration update for web server');
                   1812: }
                   1813: 
1.1       raeburn  1814: if ($callsub{'runlevels'}) {
                   1815:     my $count = 0;
                   1816:     if (ref($recommended) eq 'HASH') {
                   1817:         if (ref($recommended->{'runlevels'}) eq 'HASH') {
                   1818:             foreach my $type (keys(%{$recommended->{'runlevels'}})) {
                   1819:                 next if ($type eq 'insserv');
                   1820:                 $count ++;
                   1821:                 my $command = $recommended->{'runlevels'}{$type};
                   1822:                 if ($command ne '') {
                   1823:                     print_and_log(&mt('Runlevel update command run: [_1].',$command)."\n");
                   1824:                     system($command);
                   1825:                 }
                   1826:             }
                   1827:             if (!$count) {
                   1828:                 print_and_log(&mt('No runlevel updates required.')."\n");
                   1829:             }  
                   1830:         }
                   1831:     }
1.45.2.1  raeburn  1832:     if ($distro =~ /^(suse|sles)(\d+)/) {
                   1833:         unless(($1 eq 'sles') && ($2 >= 15)) {
                   1834:             &update_SuSEfirewall2_setup($instdir);
                   1835:         }
1.11      raeburn  1836:     }
1.1       raeburn  1837: } else {
                   1838:     &print_and_log(&mt('Skipping setting override for start-up order of services.')."\n");
                   1839: }
                   1840: 
                   1841: if ($callsub{'firewall'}) {
1.45.2.3  raeburn  1842:     my ($firewalld,$zone) = &uses_firewalld($distro);
                   1843:     if ($firewalld) {
1.45.2.1  raeburn  1844:         my (%current,%added);
1.45.2.3  raeburn  1845:         if (open(PIPE,"firewall-cmd --permanent --zone=$zone --list-services |")) {
1.45.2.1  raeburn  1846:             my $svc = <PIPE>;
                   1847:             close(PIPE);
                   1848:             chomp($svc);
                   1849:             map { $current{$_} = 1; } (split(/\s+/,$svc));
                   1850:         }
                   1851:         foreach my $service ('http','https') {
                   1852:             unless ($current{$service}) {
1.45.2.3  raeburn  1853:                 if (open(PIPE,"firewall-cmd --permanent --zone=$zone --add-service=$service |")) {
1.45.2.1  raeburn  1854:                     my $result = <PIPE>;
                   1855:                     if ($result =~ /^success/) {
                   1856:                         $added{$service} = 1;
                   1857:                     }
                   1858:                 }
                   1859:             }
                   1860:         }
                   1861:         if (keys(%added) > 0) {
                   1862:             print &mt('Firewall configured to allow access for: [_1].',
                   1863:                       join(', ',sort(keys(%added))))."\n";
1.45.2.13  raeburn  1864:             system('firewall-cmd --reload');
1.45.2.1  raeburn  1865:         }
                   1866:         if ($current{'http'} || $current{'https'}) {
                   1867:             print &mt('Firewall already configured to allow access for:[_1].',
                   1868:                       (($current{'http'})? ' http':'').(($current{'https'})? ' https':''))."\n";
                   1869:         }
                   1870:         unless ($current{'ssh'}) {
1.45.2.13  raeburn  1871:             print &mt('If you would like to allow access to ssh from outside, use the commands:')."\n".
                   1872:                   "firewall-cmd --permanent --zone=$zone --add-service=ssh\n".
                   1873:                   "firewall-cmd --reload\n";
1.45.2.1  raeburn  1874:         }
                   1875:     } elsif ($distro =~ /^(suse|sles)/) {
1.5       raeburn  1876:         print &mt('Use [_1] to configure the firewall to allow access for [_2].',
                   1877:                   'yast -- Security and Users -> Firewall -> Interfaces',
1.45.2.1  raeburn  1878:                   'ssh, http, https')."\n";
1.5       raeburn  1879:     } elsif ($distro =~ /^(debian|ubuntu)(\d+)/) {
                   1880:         if (($1 eq 'ubuntu') || ($2 > 5)) {
                   1881:             print &mt('Use [_1] to configure the firewall to allow access for [_2].',
                   1882:                       'ufw','ssh, http, https')."\n";
                   1883:         } else {
                   1884:             my $fwadded = &get_iptables_rules($distro,$instdir,$apachefw);
                   1885:             if ($fwadded) {
                   1886:                 print &mt('Enable firewall? ~[Y/n~]');
                   1887:                 my $enable_iptables = &get_user_selection(1);
                   1888:                 if ($enable_iptables) {
                   1889:                     system('/etc/network/if-pre-up.d/iptables');
                   1890:                     print &mt('Firewall enabled using rules defined in [_1].',
                   1891:                               '/etc/iptables.loncapa.rules'); 
                   1892:                 }
                   1893:             }
                   1894:         }
1.45.2.3  raeburn  1895:     } elsif ($distro =~ /^(scientific|oracle)/) {
1.11      raeburn  1896:         print &mt('Use [_1] to configure the firewall to allow access for [_2].',
                   1897:                   'system-config-firewall-tui -- Customize',
                   1898:                   'ssh, http')."\n";
1.1       raeburn  1899:     } else {
1.45.2.3  raeburn  1900:         my $version;
1.45.2.18  raeburn  1901:         if ($distro =~ /^(redhat|centos|rocky|alma)(\d+)/) {
1.45.2.3  raeburn  1902:             $version = $1;
                   1903:         }
                   1904:         if ($version > 5) {
                   1905:             print &mt('Use [_1] to configure the firewall to allow access for [_2].',
                   1906:                   'system-config-firewall-tui -- Customize',
                   1907:                   'ssh, http')."\n";
                   1908:         } else {
                   1909:             print &mt('Use [_1] to configure the firewall to allow access for [_2].',
                   1910:                       'setup -- Firewall configuration -> Customize',
                   1911:                       'ssh, http, https')."\n";
                   1912:         }
1.1       raeburn  1913:     }
                   1914: } else {
1.5       raeburn  1915:     &print_and_log(&mt('Skipping Firewall configuration.')."\n");
1.1       raeburn  1916: }
                   1917: 
                   1918: if ($callsub{'stopsrvcs'}) {
1.45      raeburn  1919:     &kill_extra_services($distro,$recommended->{'stopsrvcs'},$uses_systemctl);
1.1       raeburn  1920: } else {
1.10      raeburn  1921:     &print_and_log(&mt('Skipping stopping unnecessary service ([_1] daemons).',"'cups','memcached'")."\n");
1.1       raeburn  1922: }
                   1923: 
                   1924: my ($have_tarball,$updateshown);
                   1925: if ($callsub{'download'}) {
                   1926:     ($have_tarball,$updateshown) = &download_loncapa($instdir,$sourcetarball);
                   1927: } else {
                   1928:     print_and_log(&mt('Skipping download of LON-CAPA tar file.')."\n\n");
                   1929:     print &mt('LON-CAPA is available for download from: [_1]',
                   1930:               'http://install.loncapa.org/')."\n";
                   1931:     if (!-e '/etc/loncapa-release') {
1.45.2.19  raeburn  1932:         &print_and_log(&mt('LON-CAPA is not yet installed on your system.')."\n\n");
                   1933:         unless ($filetouse) {
                   1934:             &print_and_log(&mt('You may retrieve the source for LON-CAPA by executing:')."\n".
                   1935:                            "wget http://install.loncapa.org/versions/$lctarball\n");
                   1936:         }
1.1       raeburn  1937:     } else {
                   1938:         my $currentversion;
                   1939:         if (open(my $fh,"</etc/loncapa-release")) {
                   1940:             my $version = <$fh>;
                   1941:             chomp($version);
                   1942:             if ($version =~ /^\QLON-CAPA release \E([\w\-.]+)$/) {
                   1943:                 $currentversion = $1;
                   1944:             }
                   1945:         }
                   1946:         if ($currentversion ne '') {
                   1947:             print &mt('Version of LON-CAPA currently installed on this server is: [_1].',
                   1948:                       $currentversion),"\n";
                   1949:             if ($production) {
                   1950:                 print &mt('The latest production release of LON-CAPA is [_1].',$production)."\n";
                   1951:             }
                   1952:             if ($testing) {
                   1953:                 print &mt('The latest testing release of LON-CAPA is [_1].',$testing)."\n";
                   1954:             }
                   1955:         }
                   1956:     }
                   1957:     if ($filetouse ne '') {
                   1958:         $have_tarball = 1;
                   1959:     }
                   1960: }
                   1961: 
                   1962: print "\n".&mt('Requested configuration complete.')."\n\n";
                   1963: if ($have_tarball && !$updateshown) {
                   1964:     my ($lcdir) = ($sourcetarball =~ /^([\w.\-]+)\.tar.gz$/);
1.45.2.16  raeburn  1965:     if ($lcdir eq 'loncapa-current') {
                   1966:         $lcdir = "loncapa-X.Y.Z (X.Y.Z should correspond to a version number like '2.11.3')";
                   1967:     }
1.45.2.14  raeburn  1968:     my ($apachename,$lc_uses_systemctl,$uses_sudo);
1.45.2.12  raeburn  1969:     if ($distro =~ /^(suse|sles|debian|ubuntu)([\d.]+)/) {
                   1970:         if (($1 eq 'suse') && ($2 < 10)) {
                   1971:             $apachename = 'apache';
                   1972:         } else {
                   1973:             $apachename = 'apache2';
                   1974:         }
                   1975:     } else {
                   1976:         $apachename = 'httpd';
                   1977:     }
                   1978:     if ($distro =~ /^oracle(\d+)$/) {
                   1979:         if ($1 > 6) {
                   1980:             $lc_uses_systemctl = 1;
                   1981:         }
1.45.2.18  raeburn  1982:     } elsif ($distro =~ /^(?:rhes|centos|rocky|alma)(\d+)/) {
1.45.2.12  raeburn  1983:         if ($1 > 7) {
                   1984:             $lc_uses_systemctl = 1;
                   1985:         }
                   1986:     } elsif ($distro =~ /^ubuntu(\d+)$/) {
                   1987:         if ($1 > 16) {
                   1988:             $lc_uses_systemctl = 1;
                   1989:         }
                   1990:         $uses_sudo = 1;
1.45.2.19  raeburn  1991:     } elsif ($distro =~ /^debian(\d+)$/) {
                   1992:         if ($1 >= 10) {
                   1993:             $lc_uses_systemctl = 1;
                   1994:         }
1.45.2.12  raeburn  1995:     } elsif ($distro =~ /^sles(\d+)$/) {
                   1996:         if ($1 > 12) {
                   1997:             $lc_uses_systemctl = 1;
                   1998:         }
1.45.2.20  raeburn  1999:     } elsif ($distro =~ /^fedora(\d+)$/) {
                   2000:         if ($1 > 25) {
                   2001:             $lc_uses_systemctl = 1;
                   2002:         }
1.45.2.12  raeburn  2003:     }
1.1       raeburn  2004:     if (!-e '/etc/loncapa-release') {
                   2005:         print &mt('If you are now ready to install LON-CAPA, enter the following commands:')."\n\n";
                   2006:     } else {
1.45.2.12  raeburn  2007:         my $lcstop = '/etc/init.d/loncontrol stop';
                   2008:         if ($lc_uses_systemctl) {
                   2009:             $lcstop = 'systemctl stop loncontrol';
                   2010:         }
                   2011:         my $apachestop = "/etc/init.d/$apachename stop";
                   2012:         if ($uses_systemctl) {
                   2013:             $apachestop = "systemctl stop $apachename";
                   2014:         }
                   2015:         if ($uses_sudo) {
1.45.2.16  raeburn  2016:             $lcstop = 'sudo '.$lcstop;
1.45.2.12  raeburn  2017:             $apachestop = 'sudo '.$apachestop;
1.1       raeburn  2018:         }
1.45.2.12  raeburn  2019:         print &mt('If you are now ready to update LON-CAPA, enter the following commands:').
                   2020:               "\n\n$lcstop\n$apachestop\n";
1.1       raeburn  2021:     }
1.45.2.16  raeburn  2022:     my ($extract,$update);
                   2023:     my $homedir = '/root';
                   2024:     if ($uses_sudo) {
                   2025:         $extract = 'sudo ';
                   2026:         $update = 'sudo ';
                   2027:         if ($instdir ne $homedir) {
                   2028:             ($homedir) = ($instdir =~ m{^(.*)/[^/]+$});
                   2029:         }
                   2030:     }
                   2031:     $extract .= "tar zxf $sourcetarball --directory $homedir";
                   2032:     $update .= './UPDATE';
                   2033:     print "$extract\n".
                   2034:           "cd $homedir/$lcdir\n".
                   2035:           "$update\n";
1.1       raeburn  2036:     if (-e '/etc/loncapa-release') {
1.45.2.19  raeburn  2037:         my $lcstart = '/etc/init.d/loncontrol start';
1.45.2.12  raeburn  2038:         if ($lc_uses_systemctl) {
                   2039:             $lcstart = '/home/httpd/perl/loncontrol start';
                   2040:         }
                   2041:         my $apachestart = "/etc/init.d/$apachename start";
                   2042:         if ($uses_systemctl) {
                   2043:             $apachestart = "systemctl start $apachename";
                   2044:         }
                   2045:         if ($uses_sudo) {
                   2046:             $lcstart = 'sudo '.$lcstart;
                   2047:             $apachestart = 'sudo '.$apachestart;
                   2048:         }
                   2049:         print "$lcstart\n";
                   2050:         print "$apachestart\n";
1.1       raeburn  2051:     }
                   2052: }
                   2053: exit;
                   2054: 
                   2055: #
                   2056: # End main script
                   2057: #
                   2058: 
                   2059: #
                   2060: # Routines for the actions
                   2061: #
                   2062:  
                   2063: sub setup_www {
                   2064:     ##
                   2065:     ## Set up www
                   2066:     ##
                   2067:     print_and_log(&mt('Creating user [_1]',"'www'")."\n");
                   2068:     # -- Add group
                   2069: 
                   2070:     my $status = `/usr/sbin/groupadd www`;
                   2071:     if ($status =~ /\QGroup `www' already exists.\E/) {
                   2072:         print &mt('Group [_1] already exists.',"'www'")."\n";
                   2073:     } elsif ($status ne '') {
                   2074:         print &mt('Unable to add group [_1].',"'www'")."\n";
                   2075:     }
                   2076:    
                   2077:     my $gid = getgrnam('www');
                   2078: 
                   2079:     if (open (PIPE, "/usr/sbin/useradd -c LONCAPA -g $gid www 2>&1 |")) {
                   2080:         $status = <PIPE>;
                   2081:         close(PIPE);
                   2082:         chomp($status);
                   2083:         if ($status =~ /\QAccount `www' already exists.\E/) {
                   2084:             print &mt('Account [_1] already exists.',"'www'")."\n";
                   2085:         } elsif ($status ne '') {
                   2086:             print &mt('Unable to add user [_1].',"'www'")."\n";
                   2087:         }
                   2088:     }  else {
                   2089:         print &mt('Unable to run command to add user [_1].',"'www'")."\n";
                   2090:     }
                   2091: 
                   2092:     my $uid = &uid_of_www();
                   2093:     if (($gid ne '') && ($uid ne '')) {
                   2094:         if (!-e '/home/www') {
                   2095:             mkdir('/home/www',0755);
                   2096:             system('chown www:www /home/www');
                   2097:         }
                   2098:     }
                   2099:     writelog ($status);
                   2100: }
                   2101: 
                   2102: sub uid_of_www {
                   2103:     my ($num) = (getpwnam('www'))[2];
                   2104:     return $num;
                   2105: }
                   2106: 
                   2107: sub build_and_install_mod_auth_external {
                   2108:     my ($instdir) = @_;
                   2109:     my $num = &uid_of_www();
                   2110:     # Patch pwauth
                   2111:     print_and_log(&mt('Building authentication system for LON-CAPA users.')."\n");
                   2112:     my $patch = <<"ENDPATCH";
                   2113: 148c148
                   2114: < #define SERVER_UIDS 99		/* user "nobody" */
                   2115: ---
                   2116: > #define SERVER_UIDS $num		/* user "www" */
                   2117: ENDPATCH
                   2118: 
1.45.2.19  raeburn  2119:     my $patch_code = <<"ENDPATCH";
                   2120: 127a128
                   2121: > #include <string.h>
                   2122: 214a216
                   2123: > #include <time.h>
                   2124: 566c568
                   2125: < check_fails()
                   2126: ---
                   2127: > int check_fails()
                   2128: 589c591
                   2129: < log_failure()
                   2130: ---
                   2131: > void log_failure()
                   2132: 629c631
                   2133: < snooze(int seconds)
                   2134: ---
                   2135: > void snooze(int seconds)
                   2136: 653c655
                   2137: < main(int argc, char **argv)
                   2138: ---
                   2139: > int main(int argc, char **argv)
                   2140: ENDPATCH
                   2141: 
1.1       raeburn  2142:     if (! -e "/usr/bin/patch") {
                   2143: 	print_and_log(&mt('You must install the software development tools package: [_1], when installing Linux.',"'patch'")."\n");
                   2144:         print_and_log(&mt('Authentication installation not completed.')."\n");
                   2145:         return;
                   2146:     }
                   2147:     if (&skip_if_nonempty(`cd /tmp; tar zxf $instdir/pwauth-2.2.8.tar.gz`,
                   2148: 		     &mt('Unable to extract pwauth')."\n")) {
                   2149:         return;
                   2150:     }
                   2151:     my $dir = "/tmp/pwauth-2.2.8";
1.45.2.19  raeburn  2152:     my $patchedok;
1.1       raeburn  2153:     if (open(PATCH,"| patch $dir/config.h")) {
                   2154:         print PATCH $patch;
                   2155:         close(PATCH);
1.45.2.19  raeburn  2156:         if (open(PATCH,"| patch $dir/pwauth.c")) {
                   2157:             print PATCH $patch_code;
                   2158:             close(PATCH);
                   2159:             $patchedok = 1;
                   2160:         }
                   2161:     }
                   2162:     if ($patchedok) {
1.1       raeburn  2163:         print_and_log("\n");
                   2164:         ##
                   2165:         ## Compile patched pwauth
                   2166:         ##
                   2167:         print_and_log(&mt('Compiling pwauth')."\n");
1.12      raeburn  2168:         my $result = `cd $dir/; make 2>/dev/null `;
1.1       raeburn  2169:         my $expected = <<"END";
                   2170: gcc -g    -c -o pwauth.o pwauth.c
                   2171: gcc -o pwauth -g  pwauth.o -lcrypt
                   2172: END
                   2173:         if ($result eq $expected) {
                   2174:             print_and_log(&mt('Apparent success compiling pwauth:').
                   2175:                           "\n".$result );
                   2176:             # Install patched pwauth
                   2177:             print_and_log(&mt('Copying pwauth to [_1]',' /usr/local/sbin')."\n");
                   2178:             if (copy "$dir/pwauth","/usr/local/sbin/pwauth") {
1.5       raeburn  2179:                 if (chmod(06755, "/usr/local/sbin/pwauth")) {
1.1       raeburn  2180:                     print_and_log(&mt('[_1] copied successfully',"'pwauth'").
                   2181:                                   "\n");
                   2182:                 } else {
                   2183:                     print &mt('Unable to set permissions on [_1].'.
                   2184:                               "/usr/local/sbin/pwauth")."\n";
                   2185:                 }
                   2186:             } else {
                   2187:                 print &mt('Unable to copy [_1] to [_2]',
                   2188:                           "'$dir/pwauth'","/usr/local/sbin/pwauth")."\n$!\n";
                   2189:             }
                   2190:         } else {
                   2191:             print &mt('Unable to compile patched [_1].'."'pwauth'")."\n";
                   2192:         }
                   2193:     } else {
                   2194:         print &mt('Unable to start patch for [_1]',"'pwauth'")."\n";
                   2195:     }
                   2196:     print_and_log("\n");
                   2197: }
                   2198: 
                   2199: sub kill_extra_services {
1.45      raeburn  2200:     my ($distro,$stopsrvcs,$uses_systemctl) = @_;
1.1       raeburn  2201:     if (ref($stopsrvcs) eq 'HASH') {
                   2202:         my @stopping = sort(keys(%{$stopsrvcs}));
                   2203:         if (@stopping) {
1.6       raeburn  2204:             my $kill_list = join("', '",@stopping);
1.1       raeburn  2205:             if ($kill_list) {
                   2206:                 $kill_list = "'".$kill_list."'";
1.6       raeburn  2207:                 &print_and_log("\n".&mt('Killing unnecessary services ([_1] daemon(s)).',$kill_list)."\n");
                   2208:                 foreach my $service (@stopping) {
                   2209:                     my $daemon = $service;
                   2210:                     if ($service eq 'cups') {
                   2211:                         $daemon = 'cupsd';
                   2212:                         if ($distro =~ /^(?:debian|ubuntu)(\d+)/) {
                   2213:                             my $version = $1;
                   2214:                             if (($distro =~ /^ubuntu/) && ($version <= 8)) {
                   2215:                                 $daemon = 'cupsys';
                   2216:                             }
1.12      raeburn  2217:                         } else {
1.8       raeburn  2218:                             $daemon = 'cups';
1.6       raeburn  2219:                         }
                   2220:                     }
1.12      raeburn  2221:                     my $cmd = "ps -ef |grep '$daemon' |grep -v grep";
                   2222:                     if (open(PIPE,'-|',$cmd)) {
                   2223:                         my $daemonrunning = <PIPE>;
                   2224:                         chomp($daemonrunning);
                   2225:                         close(PIPE);
                   2226:                         if ($daemonrunning) {
                   2227:                             &print_and_log(`/etc/init.d/$daemon stop`);
                   2228:                         }
                   2229:                     }
1.1       raeburn  2230: 	            &print_and_log(&mt('Removing [_1] from startup.',$service)."\n");
1.45      raeburn  2231:                     if ($distro =~ /^(?:debian|ubuntu)(\d+)/) {
                   2232:                         my $version = $1;
1.45.2.19  raeburn  2233:                         if ((($distro =~ /^ubuntu/) && ($version > 16)) ||
                   2234:                             (($distro =~ /^debian/) && ($version >= 10))) {
1.45      raeburn  2235:                             if (ref($uses_systemctl) eq 'HASH') {
                   2236:                                 if ($uses_systemctl->{$service}) {
                   2237:                                     if (`systemctl is-enabled $service`) {
                   2238:                                         &print_and_log(`systemctl disable $service`);
                   2239:                                     }
                   2240:                                 }
                   2241:                             }
                   2242:                         } else {
                   2243:                             &print_and_log(`update-rc.d -f $daemon remove`);
                   2244:                         }
1.1       raeburn  2245:                     } else {
1.35      raeburn  2246:                         if (ref($uses_systemctl) eq 'HASH') {
                   2247:                             if ($uses_systemctl->{$service}) {
                   2248:                                 if (`systemctl is-enabled $service`) {                          
                   2249:                                     &print_and_log(`systemctl disable $service`);
                   2250:                                 }
                   2251:                             } else {
                   2252:                                 &print_and_log(`/sbin/chkconfig --del $service`);
                   2253:                             }
                   2254:                         } else {
                   2255: 	                    &print_and_log(`/sbin/chkconfig --del $service`);
                   2256:                         } 
1.1       raeburn  2257:                     }
                   2258:                 }
                   2259:             }
                   2260:         }
                   2261:     }
                   2262:     return;
                   2263: }
                   2264: 
                   2265: sub setup_mysql {
1.45.2.15  raeburn  2266:     my ($setup_mysql_permissions,$dbh,$has_pass,$mysql_unix_socket,$has_lcdb,$distro) = @_;
1.4       raeburn  2267:     my @mysql_lc_commands;
1.1       raeburn  2268:     unless ($has_lcdb) {
1.45.2.15  raeburn  2269:         my $createcmd = 'CREATE DATABASE loncapa';
                   2270:         if ($distro =~ /^sles(\d+)/) {
                   2271:             if ($1 > 11) {
                   2272:                 $createcmd .= ' CHARACTER SET utf8 COLLATE utf8_general_ci';
                   2273:             }
                   2274:         } elsif ($distro =~ /^ubuntu(\d+)/) {
                   2275:             if ($1 > 16) {
                   2276:                 $createcmd .= ' CHARACTER SET latin1 COLLATE latin1_swedish_ci';
                   2277:             }
                   2278:         }
                   2279:         push(@mysql_lc_commands,$createcmd);
1.1       raeburn  2280:     }
1.4       raeburn  2281:     push(@mysql_lc_commands,"USE loncapa");
                   2282:     push(@mysql_lc_commands,qq{
1.18      raeburn  2283: CREATE TABLE IF NOT EXISTS metadata (title TEXT, author TEXT, subject TEXT, url TEXT, keywords TEXT, version TEXT, notes TEXT, abstract TEXT, mime TEXT, language TEXT, creationdate DATETIME, lastrevisiondate DATETIME, owner TEXT, copyright TEXT, domain TEXT, dependencies TEXT, modifyinguser TEXT, authorspace TEXT, lowestgradelevel TEXT, highestgradelevel TEXT, standards TEXT, count INT, course INT, course_list TEXT, goto INT, goto_list TEXT, comefrom INT, comefrom_list TEXT, sequsage INT, sequsage_list TEXT, stdno INT, stdno_list TEXT, avetries FLOAT, avetries_list TEXT, difficulty FLOAT, difficulty_list TEXT, disc FLOAT, disc_list TEXT, clear FLOAT, technical FLOAT, correct FLOAT, helpful FLOAT, depth FLOAT, hostname TEXT, FULLTEXT idx_title (title), FULLTEXT idx_author (author), FULLTEXT idx_subject (subject), FULLTEXT idx_url (url), FULLTEXT idx_keywords (keywords), FULLTEXT idx_version (version), FULLTEXT idx_notes (notes), FULLTEXT idx_abstract (abstract), FULLTEXT idx_mime (mime), FULLTEXT idx_language (language), FULLTEXT idx_owner (owner), FULLTEXT idx_copyright (copyright)) ENGINE=MYISAM
1.4       raeburn  2284: });
1.1       raeburn  2285:     if ($setup_mysql_permissions) {
1.45.2.9  raeburn  2286:         &setup_mysql_permissions($dbh,$has_pass,$mysql_unix_socket,@mysql_lc_commands);
1.1       raeburn  2287:     } else {
                   2288:         print_and_log(&mt('Skipping MySQL permissions setup.')."\n");
                   2289:         if ($dbh) {
1.4       raeburn  2290:             if (@mysql_lc_commands) {
                   2291:                 foreach my $lccmd (@mysql_lc_commands) { 
                   2292:                     $dbh->do($lccmd) || print $dbh->errstr."\n";
                   2293:                 }
                   2294:             }
1.1       raeburn  2295:             print_and_log(&mt('MySQL database set up complete.')."\n");
                   2296:         } else {
                   2297:             print_and_log(&mt('Problem accessing MySQL.')."\n");
                   2298:         }
                   2299:     }
                   2300: }
                   2301: 
                   2302: sub setup_mysql_permissions {
1.45.2.9  raeburn  2303:     my ($dbh,$has_pass,$mysql_unix_socket,@mysql_lc_commands) = @_;
1.45.2.19  raeburn  2304:     my ($mysqlversion,$mysqlminorversion,$mysqlsubver,$mysqlname) = &get_mysql_version();
1.45.2.9  raeburn  2305:     my ($usescreate,$usesauth,$is_mariadb,$hasauthcol,@mysql_commands);
1.38      raeburn  2306:     if ($mysqlname =~ /^MariaDB/i) {
1.45.2.2  raeburn  2307:         $is_mariadb = 1;
1.45.2.19  raeburn  2308:         if ((($mysqlversion == 10) && ($mysqlminorversion >= 4)) || ($mysqlversion >= 11)) {
1.45.2.9  raeburn  2309:             $usescreate = 1;
1.45.2.19  raeburn  2310:         } elsif (($mysqlversion == 10) && ($mysqlminorversion >= 2)) {
1.38      raeburn  2311:             $usesauth = 1;
1.45.2.19  raeburn  2312:         } elsif (($mysqlversion == 5) && ($mysqlminorversion >= 5)) {
1.42      raeburn  2313:             $hasauthcol = 1;
1.38      raeburn  2314:         }
                   2315:     } else {
1.45.2.19  raeburn  2316:         if (($mysqlversion > 5) || (($mysqlminorversion == 5) && ($mysqlminorversion > 7)) ||
                   2317:             (($mysqlversion == 5) && ($mysqlminorversion == 7) && ($mysqlsubver > 5))) {
1.38      raeburn  2318:             $usesauth = 1;
1.45.2.19  raeburn  2319:         } elsif (($mysqlversion == 5) &&
                   2320:                  (($mysqlminorversion >= 6) || (($mysqlminorversion == 5) && ($mysqlsubver >= 7)))) {
1.42      raeburn  2321:             $hasauthcol = 1;
1.38      raeburn  2322:         }
                   2323:     }
1.45.2.9  raeburn  2324:     if ($usescreate) {
                   2325:         @mysql_commands = ("CREATE USER 'www'\@'localhost' IDENTIFIED BY 'localhostkey'");
                   2326:     } elsif ($usesauth) {
1.45.2.15  raeburn  2327:         @mysql_commands = ("INSERT user (Host, User, ssl_cipher, x509_issuer, x509_subject, authentication_string) VALUES('localhost','www','','','','')",
                   2328:                            "FLUSH PRIVILEGES");
1.45.2.2  raeburn  2329:         if ($is_mariadb) {
                   2330:             push(@mysql_commands,"ALTER USER 'www'\@'localhost' IDENTIFIED BY 'localhostkey'");
                   2331:         } else {
                   2332:             push(@mysql_commands,"ALTER USER 'www'\@'localhost' IDENTIFIED WITH mysql_native_password BY 'localhostkey'");
                   2333:         }
1.42      raeburn  2334:     } elsif ($hasauthcol) {
                   2335:         @mysql_commands = ("INSERT user (Host, User, Password, ssl_cipher, x509_issuer, x509_subject, authentication_string) VALUES('localhost','www',password('localhostkey'),'','','','');");
1.36      raeburn  2336:     } else {
1.42      raeburn  2337:         @mysql_commands = ("INSERT user (Host, User, Password, ssl_cipher, x509_issuer, x509_subject) VALUES('localhost','www',password('localhostkey'),'','','');");
1.36      raeburn  2338:     }
1.1       raeburn  2339:     if ($mysqlversion < 4) {
1.4       raeburn  2340:         push (@mysql_commands,"
                   2341: INSERT db (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Grant_priv,References_priv,Index_priv,Alter_priv) VALUES('localhost','loncapa','www','Y','Y','Y','Y','Y','Y','N','Y','Y','Y')");
                   2342:     } else {
                   2343:         push (@mysql_commands,"
                   2344: INSERT db (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Grant_priv,References_priv,Index_priv,Alter_priv,Create_tmp_table_priv,Lock_tables_priv) VALUES('localhost','loncapa','www','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y')");
1.1       raeburn  2345:     }
1.4       raeburn  2346:     push(@mysql_commands,"DELETE FROM user WHERE host<>'localhost'");
1.45.2.9  raeburn  2347:     if (($has_pass) || ($mysql_unix_socket)) {
1.1       raeburn  2348:         if ($dbh) {
1.4       raeburn  2349:             push(@mysql_commands,"FLUSH PRIVILEGES");
                   2350:             if (@mysql_commands) {
                   2351:                 foreach my $cmd (@mysql_commands) {
                   2352:                     $dbh->do($cmd) || print $dbh->errstr."\n";
                   2353:                 }
                   2354:             }
                   2355:             if (@mysql_lc_commands) {
                   2356:                 foreach my $lccmd (@mysql_lc_commands) {
                   2357:                     $dbh->do($lccmd) || print $dbh->errstr."\n";
                   2358:                 }
                   2359:             }
1.1       raeburn  2360:             print_and_log(&mt('Permissions set for LON-CAPA MySQL user: [_1]',"'www'")."\n");
                   2361:         } else {
                   2362:             print_and_log(&mt('Problem accessing MySQL.')."\n".
                   2363:                           &mt('Permissions not set.')."\n");
                   2364:         }
                   2365:     } else {
                   2366:         my ($firstpass,$secondpass,$got_passwd,$newmysqlpass);
                   2367:         print &mt('Please enter a root password for the mysql database.')."\n".
                   2368:               &mt('It does not have to match your root account password, but you will need to remember it.')."\n";
                   2369:         my $maxtries = 10;
                   2370:         my $trial = 0;
                   2371:         while ((!$got_passwd) && ($trial < $maxtries)) {
                   2372:             $firstpass = &get_mysql_password(&mt('Enter password'));
                   2373:             if (length($firstpass) > 5) { 
                   2374:                 $secondpass = &get_mysql_password(&mt('Enter password a second time'));
                   2375:                 if ($firstpass eq $secondpass) {
                   2376:                     $got_passwd = 1;
                   2377:                     $newmysqlpass = $firstpass;
                   2378:                 } else {
                   2379:                     print(&mt('Passwords did not match. Please try again.')."\n");
                   2380:                 }
                   2381:                 $trial ++;
                   2382:             } else {
                   2383:                 print(&mt('Password too short.')."\n".
                   2384:                       &mt('Please choose a password with at least six characters.')."\n");
                   2385:             }
                   2386:         }
                   2387:         if ($got_passwd) {
1.45.2.2  raeburn  2388:             my (@newpass_cmds) = &new_mysql_rootpasswd($newmysqlpass,$usesauth,$is_mariadb);
1.4       raeburn  2389:             push(@mysql_commands,@newpass_cmds);
1.1       raeburn  2390:         } else {
                   2391:             print_and_log(&mt('Failed to get MySQL root password from user input.')."\n");
                   2392:         }
                   2393:         if ($dbh) {
1.4       raeburn  2394:             if (@mysql_commands) {
                   2395:                 foreach my $cmd (@mysql_commands) {
                   2396:                     $dbh->do($cmd) || print $dbh->errstr."\n";
                   2397:                 }
                   2398:             }
                   2399:             if (@mysql_lc_commands) {
                   2400:                 foreach my $lccmd (@mysql_lc_commands) {
                   2401:                     $dbh->do($lccmd) || print $dbh->errstr."\n";
                   2402:                 }
                   2403:             }
1.1       raeburn  2404:             if ($got_passwd) {
                   2405:                 print_and_log(&mt('MySQL root password stored.')."\n".
                   2406:                               &mt('Permissions set for LON-CAPA MySQL user: [_1].',"'www'")."\n");
                   2407:             } else {
                   2408:                 print_and_log(&mt('Permissions set for LON-CAPA MySQL user: [_1].',"'www'")."\n");
                   2409:             }
                   2410:         } else {
                   2411:             print_and_log(&mt('Problem accessing MySQL.')."\n".
                   2412:                           &mt('Permissions not set.')."\n");
                   2413:         }
                   2414:     }
                   2415: }
                   2416: 
                   2417: sub new_mysql_rootpasswd {
1.45.2.2  raeburn  2418:     my ($currmysqlpass,$usesauth,$is_mariadb) = @_;
1.36      raeburn  2419:     if ($usesauth) {
1.45.2.2  raeburn  2420:         if ($is_mariadb) {
                   2421:             return ("ALTER USER 'root'\@'localhost' IDENTIFIED BY '$currmysqlpass'",
                   2422:                     "FLUSH PRIVILEGES;");
                   2423:         } else {
                   2424:             return ("ALTER USER 'root'\@'localhost' IDENTIFIED WITH mysql_native_password BY '$currmysqlpass'",
                   2425:                     "FLUSH PRIVILEGES;");
                   2426:         }
1.36      raeburn  2427:     } else {
                   2428:         return ("SET PASSWORD FOR 'root'\@'localhost'=PASSWORD('$currmysqlpass')",
                   2429:                 "FLUSH PRIVILEGES;");
                   2430:     }
1.1       raeburn  2431: }
                   2432: 
                   2433: sub get_mysql_version {
1.45.2.19  raeburn  2434:     my ($version,$minorversion,$subversion,$name);
1.1       raeburn  2435:     if (open(PIPE," mysql -V |")) {
                   2436:         my $info = <PIPE>;
                   2437:         chomp($info);
                   2438:         close(PIPE);
1.45.2.19  raeburn  2439:         ($version,$minorversion,$subversion,$name) = ($info =~ /(\d+)\.(\d+)\.(\d+)(?:\-?(\w*),|)/);
1.1       raeburn  2440:     } else {
                   2441:         print &mt('Could not determine which version of MySQL is installed.').
                   2442:               "\n";
                   2443:     }
1.45.2.19  raeburn  2444:     return ($version,$minorversion,$subversion,$name);
1.1       raeburn  2445: }
                   2446: 
1.45.2.20  raeburn  2447: sub check_systemd_update {
                   2448:     my ($distro) = @_;
                   2449:     my ($use_systemctl,$service);
                   2450:     $service = 'apache2.service';
                   2451:     if ($distro =~ /^ubuntu(\w+)/) {
                   2452:         if ($1 >= 16) {
                   2453:             $use_systemctl = 1;
                   2454:         }
                   2455:     } elsif ($distro =~ /^debian(\w+)/) {
                   2456:         if ($1 >= 9) {
                   2457:             $use_systemctl = 1;
                   2458:         }
                   2459:     } elsif ($distro =~ /^fedora(\d+)/) {
                   2460:         $service = 'httpd.service';
                   2461:         if ($1 >= 16) {
                   2462:             $use_systemctl = 1;
                   2463:         }
                   2464:     } elsif ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
                   2465:         $service = 'httpd.service';
                   2466:         if ($1 >= 7) {
                   2467:             $use_systemctl = 1;
                   2468:         }
                   2469:     } elsif ($distro =~ /^sles(\d+)/) {
                   2470:         if ($1 >= 12) {
                   2471:             $use_systemctl = 1;
                   2472:         }
                   2473:     } elsif ($distro =~ /^suse(\d+)/) {
                   2474:         if ($1 >= 13) {
                   2475:             $use_systemctl = 1;
                   2476:         }
                   2477:     }
                   2478:     if ($use_systemctl) {
                   2479:         my $needsupdate = &check_systemd_security($distro);
                   2480:         if ($needsupdate) {
                   2481:             if (!-d '/etc/systemd/system/'.$service.'.d') {
                   2482:                 mkdir '/etc/systemd/system/'.$service.'.d', 0755;
                   2483:             }
                   2484:             if (-d '/etc/systemd/system/'.$service.'.d') {
                   2485:                 if (-e '/etc/systemd/system/'.$service.'.d/override.conf') {
                   2486:                     if (open(my $fh,'<','/etc/systemd/system/'.$service.'.d/override.conf')) {
                   2487:                         my ($inservice,$addservice,$protectoff,$linenum,$change,@lines);
                   2488:                         while (my $entry = <$fh>) {
                   2489:                             $linenum ++;
                   2490:                             chomp($entry);
                   2491:                             if ($entry eq '[Service]') {
                   2492:                                 if (!$protectoff) {
                   2493:                                     $inservice = $linenum;
                   2494:                                     push(@lines,$entry);
                   2495:                                 } else {
                   2496:                                     $addservice = 1;
                   2497:                                     next;
                   2498:                                 }
                   2499:                             }
                   2500:                             if ($entry =~ /^ProtectHome\s*=\s*([\w-]+)\s*$/) {
                   2501:                                 my $value = $1;
                   2502:                                 if ($protectoff) {
                   2503:                                     next;
                   2504:                                     if (lc($value) eq 'no') {
                   2505:                                         $protectoff = $linenum;
                   2506:                                         push(@lines,$entry);
                   2507:                                     } else {
                   2508:                                         if ($protectoff) {
                   2509:                                             next;
                   2510:                                         } else {
                   2511:                                             push(@lines,'ProtectHome=no');
                   2512:                                             $protectoff = $linenum;
                   2513:                                             $change = $linenum;
                   2514:                                         }
                   2515:                                     }
                   2516:                                 }
                   2517:                             }
                   2518:                         }
                   2519:                         close($fh);
                   2520:                         if ($addservice || $change || !$protectoff) {
                   2521:                             if (open(my $fh,'>','/etc/systemd/system/'.$service.'.d/override.conf')) {
                   2522:                                 if ($addservice) {
                   2523:                                     print $fh "[Service]\n";
                   2524:                                 }
                   2525:                                 foreach my $entry (@lines) {
                   2526:                                     print $fh "$entry\n";
                   2527:                                 }
                   2528:                                 close($fh);
                   2529:                                 print_and_log('Updated /etc/systemd/system/'.$service.'.d/override.conf');
1.45.2.21! raeburn  2530:                                 system('systemctl daemon-reload');
1.45.2.20  raeburn  2531:                             } else {
                   2532:                                 print_and_log('Could not open /etc/systemd/system/'.$service.'.d/override.conf for writing.');
                   2533:                             }
                   2534:                         } else {
                   2535:                             print_and_log('No change needed in /etc/systemd/system/'.$service.'.d/override.conf');
                   2536:                         }
                   2537:                     } else {
                   2538:                         print_and_log('Could not open /etc/systemd/system/'.$service.'.d/override.conf for reading.');
                   2539:                     }
                   2540:                 } else {
                   2541:                     if (open(my $fh,'>','/etc/systemd/system/'.$service.'.d/override.conf')) {
                   2542:                         print $fh '[Service]'."\n".'ProtectHome=no'."\n";
                   2543:                         close($fh);
                   2544:                         print_and_log('Created /etc/systemd/system/'.$service.'.d/override.conf');
1.45.2.21! raeburn  2545:                         system('systemctl daemon-reload');
1.45.2.20  raeburn  2546:                     }
                   2547:                 }
                   2548:             } else {
                   2549:                 print_and_log('No /etc/systemd/system/'.$service.'.d directory exists and creating one failed,');
                   2550:             }
                   2551:         } else {
                   2552:             print_and_log('No update needed to systemd security settings for Apache web server.');
                   2553:         }
                   2554:     } else {
                   2555:         print_and_log('No update needed to systemd, as this Linux distro does not use systemctl');
                   2556:     }
                   2557: }
                   2558: 
1.1       raeburn  2559: ###########################################################
                   2560: ##
                   2561: ## RHEL/CentOS/Fedora/Scientific Linux
                   2562: ## Copy LON-CAPA httpd.conf to /etc/httpd/conf
                   2563: ##
                   2564: ###########################################################
                   2565: 
                   2566: sub copy_httpd_conf {
1.14      raeburn  2567:     my ($instdir,$distro) = @_;
                   2568:     my $configfile = 'httpd.conf';
1.45.2.18  raeburn  2569:     if ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
1.29      raeburn  2570:         if ($1 >= 7) {
                   2571:             $configfile = 'apache2.4/httpd.conf';
                   2572:         } elsif ($1 > 5) {
1.14      raeburn  2573:             $configfile = 'new/httpd.conf';
                   2574:         }
                   2575:     } elsif ($distro =~ /^fedora(\d+)$/) {
1.29      raeburn  2576:         if ($1 > 17) {
                   2577:             $configfile = 'apache2.4/httpd.conf';
                   2578:         } elsif ($1 > 10) {
1.14      raeburn  2579:             $configfile = 'new/httpd.conf';
                   2580:         }
                   2581:     }
1.1       raeburn  2582:     print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',"'httpd.conf'",
                   2583:                   "'/etc/httpd/conf/httpd.conf'")."\n");
                   2584:     copy "/etc/httpd/conf/httpd.conf","/etc/httpd/conf/httpd.conf.original";
1.14      raeburn  2585:     copy "$instdir/centos-rhes-fedora-sl/$configfile","/etc/httpd/conf/httpd.conf";
1.5       raeburn  2586:     chmod(0444,"/etc/httpd/conf/httpd.conf");
1.1       raeburn  2587:     print_and_log("\n");
                   2588: }
                   2589: 
1.45.2.5  raeburn  2590: ###########################################################
                   2591: ##
                   2592: ## RHEL/CentOS/Fedora/Scientific Linux
                   2593: ## Copy LON-CAPA mpm.conf to /etc/httpd/conf.modules.d/00-mpm.conf
                   2594: ##
                   2595: ## The LON-CAPA mpm.conf enables the prefork MPM module in
                   2596: ## Apache. This is also the default for RHEL/CentOS/Oracle
                   2597: ## Linux 7 and earlier, and Fedora 26 and earlier. For more
                   2598: ## recent versions of those distros, the event MPM is enabled
                   2599: ## by default. After &copy_mpm_conf() is run, the prefork MPM
                   2600: ## module will be enabled instead of the event MPM module.
                   2601: ##
                   2602: ###########################################################
                   2603: 
                   2604: sub copy_mpm_conf {
                   2605:     my ($instdir,$distro) = @_;
                   2606:     my $mpmfile = 'mpm.conf';
                   2607:     if ((-e "/etc/httpd/conf.modules.d/00-mpm.conf") &&
                   2608:         (-e "$instdir/centos-rhes-fedora-sl/$mpmfile")) {
                   2609:         print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',"'mpm.conf'",
                   2610:                       "'/etc/httpd/conf.modules.d/00-mpm.conf'")."\n");
                   2611:         copy "$instdir/centos-rhes-fedora-sl/$mpmfile","/etc/httpd/conf.modules.d/00-mpm.conf";
                   2612:         chmod(0644,"/etc/httpd/conf.modules.d/00-mpm.conf");
                   2613:         print_and_log("\n");
                   2614:     } else {
                   2615:         my $logfail;
1.45.2.18  raeburn  2616:         if ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
1.45.2.5  raeburn  2617:             if ($1 > 7) {
                   2618:                 $logfail = 1;
                   2619:             }
                   2620:         } elsif ($distro =~ /^fedora(\d+)$/) {
                   2621:             if ($1 > 26) {
                   2622:                 $logfail = 1;
                   2623:             }
                   2624:         }
                   2625:         if ($logfail) {
                   2626:             print_and_log(&mt('Warning: copying the LON-CAPA [_1] failed because [_2] and/or [_3] are missing.',
                   2627:                               $mpmfile,"'$instdir/centos-rhes-fedora-sl/$mpmfile'",
                   2628:                               "'/etc/httpd/conf.modules.d/00-mpm.conf'"));
                   2629:             print_and_log("\n");
                   2630:         }
                   2631:     }
                   2632: }
                   2633: 
1.1       raeburn  2634: #########################################################
                   2635: ##
1.17      raeburn  2636: ## Ubuntu/Debian -- copy our loncapa configuration file to
1.1       raeburn  2637: ## sites-available and set the symlink from sites-enabled.
                   2638: ##
                   2639: #########################################################
                   2640: 
                   2641: sub copy_apache2_debconf {
1.28      raeburn  2642:     my ($instdir,$distro) = @_;
1.6       raeburn  2643:     my $apache2_mods_enabled_dir = '/etc/apache2/mods-enabled';
                   2644:     my $apache2_mods_available_dir = '/etc/apache2/mods-available';
                   2645:     foreach my $module ('headers.load','expires.load') {
                   2646:         unless (-l "$apache2_mods_enabled_dir/$module") {
                   2647:             symlink("$apache2_mods_available_dir/$module","$apache2_mods_enabled_dir/$module");
                   2648:             print_and_log(&mt('Enabling "[_1]" Apache module.',$module)."\n");
                   2649:         }
                   2650:     }
1.28      raeburn  2651:     my $apache2_sites_enabled_dir = '/etc/apache2/sites-enabled';
                   2652:     my $apache2_sites_available_dir = '/etc/apache2/sites-available';
                   2653:     my $defaultconfig = "$apache2_sites_enabled_dir/000-default";
1.45.2.10  raeburn  2654:     my $defaultsite = "$apache2_sites_enabled_dir/loncapa.conf";
1.28      raeburn  2655:     my ($distname,$version);
                   2656:     if ($distro =~ /^(debian|ubuntu)(\d+)$/) {
                   2657:         $distname = $1;
                   2658:         $version = $2;
                   2659:     }
1.45.2.19  raeburn  2660:     if ((($distname eq 'ubuntu') && ($version > 12)) ||
                   2661:         (($distname eq 'debian') && ($version >= 10))) {
1.28      raeburn  2662:         $defaultconfig = "$apache2_sites_enabled_dir/000-default.conf";
                   2663:     }
1.45.2.7  raeburn  2664:     my ($skipconf,$skipsite,$skipstatus);
1.45.2.19  raeburn  2665:     if ((($distname eq 'ubuntu') && ($version > 12)) ||
                   2666:         (($distname eq 'debian') && ($version >= 10))) {
1.28      raeburn  2667:         my $apache2_conf_enabled_dir = '/etc/apache2/conf-enabled';
                   2668:         my $apache2_conf_available_dir = '/etc/apache2/conf-available';
1.33      raeburn  2669:         my $defaultconf = $apache2_conf_enabled_dir.'/loncapa.conf';
1.45.2.7  raeburn  2670:         if ((-e "$apache2_conf_available_dir/loncapa") && (-e "$instdir/debian-ubuntu/ubuntu14/loncapa_conf")) {
1.45.2.8  raeburn  2671:             if (open(PIPE, "diff --brief $apache2_conf_available_dir/loncapa $instdir/debian-ubuntu/ubuntu14/loncapa_conf |")) {
1.45.2.7  raeburn  2672:                 my $diffres = <PIPE>;
                   2673:                 close(PIPE);
                   2674:                 chomp($diffres);
                   2675:                 if ($diffres) {
1.45.2.10  raeburn  2676:                     copy("$apache2_conf_available_dir/loncapa","$apache2_conf_available_dir/loncapa.conf.original");
                   2677:                 } else {
                   2678:                     copy("$apache2_conf_available_dir/loncapa","$apache2_conf_available_dir/loncapa.conf");
1.45.2.11  raeburn  2679:                     chdir($apache2_conf_enabled_dir);
                   2680:                     symlink('../conf-available/loncapa.conf','loncapa.conf');
                   2681:                     chdir($instdir);
1.45.2.7  raeburn  2682:                 }
                   2683:                 if (-l $defaultconf) {
                   2684:                     my $linkfname = readlink($defaultconf);
1.45.2.11  raeburn  2685:                     if ($linkfname ne '') {
                   2686:                         $linkfname = Cwd::abs_path(File::Spec->rel2abs($linkfname,$apache2_conf_enabled_dir));
                   2687:                     }
1.45.2.7  raeburn  2688:                     if ($linkfname eq "$apache2_conf_available_dir/loncapa") {
1.45.2.10  raeburn  2689:                         unlink($defaultconf);
                   2690:                     }
                   2691:                 }
                   2692:                 unlink("$apache2_conf_available_dir/loncapa");
                   2693:             }
                   2694:         }
                   2695:         if ((-e "$apache2_conf_available_dir/loncapa.conf") && (-e "$instdir/debian-ubuntu/ubuntu14/loncapa_conf")) {
                   2696:             if (open(PIPE, "diff --brief $apache2_conf_available_dir/loncapa.conf $instdir/debian-ubuntu/ubuntu14/loncapa_conf |")) {
                   2697:                 my $diffres = <PIPE>;
                   2698:                 close(PIPE);
                   2699:                 chomp($diffres);
                   2700:                 if ($diffres) {
                   2701:                     copy("$apache2_conf_available_dir/loncapa.conf","$apache2_conf_available_dir/loncapa.conf.original");
                   2702:                 }
                   2703:                 if (-l $defaultconf) {
                   2704:                     my $linkfname = readlink($defaultconf);
1.45.2.11  raeburn  2705:                     if ($linkfname ne '') {
                   2706:                         $linkfname = Cwd::abs_path(File::Spec->rel2abs($linkfname,$apache2_conf_enabled_dir));
                   2707:                     }
1.45.2.10  raeburn  2708:                     if ($linkfname eq "$apache2_conf_available_dir/loncapa.conf") {
1.45.2.7  raeburn  2709:                         unless ($diffres) {
                   2710:                             $skipconf = 1;
                   2711:                         }
                   2712:                     }
                   2713:                 }
                   2714:             }
                   2715:         }
                   2716:         unless ($skipconf) {
                   2717:             print_and_log(&mt('Copying loncapa [_1] config file to [_2] and pointing [_3] to it from conf-enabled.',"'apache2'","'/etc/apache2/conf-available'","'loncapa.conf symlink'")."\n");
1.45.2.10  raeburn  2718:             copy("$instdir/debian-ubuntu/ubuntu14/loncapa_conf","$apache2_conf_available_dir/loncapa.conf");
                   2719:             chmod(0444,"$apache2_conf_available_dir/loncapa.conf");
1.45.2.7  raeburn  2720:             if (-l $defaultconf) {
                   2721:                 unlink($defaultconf);
                   2722:             }
1.45.2.11  raeburn  2723:             chdir($apache2_conf_enabled_dir);
                   2724:             symlink('../conf-available/loncapa.conf','loncapa.conf');
                   2725:             chdir($instdir);
1.45.2.7  raeburn  2726:         }
                   2727:         my $stdsite = "$instdir/debian-ubuntu/ubuntu14/loncapa_site";
                   2728:         if ((-e $stdsite) && (-e "$apache2_sites_available_dir/loncapa")) {
                   2729:             if (open(PIPE, "diff --brief $stdsite $apache2_sites_available_dir/loncapa |")) {
                   2730:                 my $diffres = <PIPE>;
                   2731:                 close(PIPE);
                   2732:                 chomp($diffres);
                   2733:                 if ($diffres) {
1.45.2.10  raeburn  2734:                     copy("$apache2_sites_available_dir/loncapa","$apache2_sites_available_dir/loncapa.conf.original");
                   2735:                 } else {
                   2736:                     copy("$apache2_sites_available_dir/loncapa","$apache2_sites_available_dir/loncapa.conf");
1.45.2.7  raeburn  2737:                 }
                   2738:                 if (-l $defaultconfig) {
                   2739:                     my $linkfname = readlink($defaultconfig);
1.45.2.11  raeburn  2740:                     if ($linkfname ne '') {
                   2741:                         $linkfname = Cwd::abs_path(File::Spec->rel2abs($linkfname,$apache2_sites_enabled_dir));
                   2742:                     }
1.45.2.7  raeburn  2743:                     if ($linkfname eq "$apache2_sites_available_dir/loncapa") {
1.45.2.10  raeburn  2744:                         unlink($defaultconfig);
                   2745:                     }
                   2746:                 }
                   2747:                 unlink("$apache2_sites_available_dir/loncapa");
                   2748:             }
                   2749:         }
                   2750:         if ((-e $stdsite) && (-e "$apache2_sites_available_dir/loncapa.conf")) {
                   2751:             if (open(PIPE, "diff --brief $stdsite $apache2_sites_available_dir/loncapa.conf |")) {
                   2752:                 my $diffres = <PIPE>;
                   2753:                 close(PIPE);
                   2754:                 chomp($diffres);
                   2755:                 if ($diffres) {
                   2756:                     copy("$apache2_sites_available_dir/loncapa.conf","$apache2_sites_available_dir/loncapa.conf.original");
                   2757:                 }
                   2758:                 if (-l $defaultsite) {
                   2759:                     my $linkfname = readlink($defaultsite);
1.45.2.11  raeburn  2760:                     if ($linkfname ne '') {
                   2761:                         $linkfname = Cwd::abs_path(File::Spec->rel2abs($linkfname,$apache2_sites_enabled_dir));
                   2762:                     }
                   2763:                     if ($linkfname eq "$apache2_sites_available_dir/loncapa.conf") {
1.45.2.7  raeburn  2764:                         unless ($diffres) {
                   2765:                             $skipsite = 1;
                   2766:                         }
                   2767:                     }
                   2768:                 }
                   2769:             }
                   2770:         }
                   2771:         unless ($skipsite) {
1.45.2.10  raeburn  2772:             print_and_log(&mt('Copying loncapa [_1] site file to [_2] and pointing [_3] to it from sites-enabled.',"'apache2'","'/etc/apache2/sites-available'","'loncapa.conf symlink'")."\n");
                   2773:             copy("$instdir/debian-ubuntu/ubuntu14/loncapa_site","$apache2_sites_available_dir/loncapa.conf");
                   2774:             chmod(0444,"$apache2_sites_available_dir/loncapa.conf");
1.45.2.11  raeburn  2775:             chdir($apache2_sites_enabled_dir);
                   2776:             symlink('../sites-available/loncapa.conf','loncapa.conf');
                   2777:             chdir($instdir);
1.45.2.10  raeburn  2778:         }
1.45.2.11  raeburn  2779:         if (-l $defaultconfig) {
1.45.2.10  raeburn  2780:             my $linkfname = readlink($defaultconfig);
1.45.2.11  raeburn  2781:             if ($linkfname ne '') {
                   2782:                 $linkfname = Cwd::abs_path(File::Spec->rel2abs($linkfname,$apache2_sites_enabled_dir));
                   2783:             }
                   2784:             if ($linkfname eq "$apache2_sites_available_dir/000-default.conf") {
1.45.2.10  raeburn  2785:                 unlink($defaultconfig);
                   2786:             }
1.45.2.7  raeburn  2787:         }
                   2788:     } else {
                   2789:         if ((-e "$instdir/debian-ubuntu/loncapa") && (-e "$apache2_sites_available_dir/loncapa")) {
                   2790:             if (open(PIPE, "diff --brief $instdir/debian-ubuntu/loncapa $apache2_sites_available_dir/loncapa |")) {
                   2791:                 my $diffres = <PIPE>;
                   2792:                 close(PIPE);
                   2793:                 chomp($diffres);
                   2794:                 if ($diffres) {
                   2795:                     copy("$apache2_sites_available_dir/loncapa","$apache2_sites_available_dir/loncapa.original");
                   2796:                 }
                   2797:                 if (-l $defaultconfig) {
                   2798:                     my $linkfname = readlink($defaultconfig);
                   2799:                     if ($linkfname eq "$apache2_sites_available_dir/loncapa") {
                   2800:                         unless ($diffres) {
                   2801:                             $skipsite = 1;
                   2802:                         }
                   2803:                     }
                   2804:                 }
                   2805:             }
                   2806:         }
                   2807:         unless ($skipsite) {
                   2808:             if (-l $defaultconfig) {
                   2809:                 unlink($defaultconfig);
                   2810:             }
                   2811:             print_and_log(&mt('Copying loncapa [_1] config file to [_2] and pointing [_3] to it from sites-enabled.',"'apache2'","'/etc/apache2/sites-available'","'000-default symlink'")."\n");
                   2812:             if (-e "$instdir/debian-ubuntu/loncapa") {
                   2813:                 copy("$instdir/debian-ubuntu/loncapa","$apache2_sites_available_dir/loncapa");
                   2814:                 chmod(0444,"$apache2_sites_available_dir/loncapa");
                   2815:                 symlink("$apache2_sites_available_dir/loncapa","$apache2_sites_enabled_dir/000-default");
                   2816:             }
                   2817:         }
                   2818:     }
1.45.2.19  raeburn  2819:     if (($distname eq 'ubuntu') || ($distname eq 'debian')) {
1.45.2.7  raeburn  2820:         my $sitestatus = "$apache2_mods_available_dir/status.conf";
                   2821:         my $stdstatus = "$instdir/debian-ubuntu/status.conf";
                   2822:         if ((-e $sitestatus) && (-e $stdstatus)) {
                   2823:             if (open(PIPE, "diff --brief $stdstatus $sitestatus |")) {
                   2824:                 my $diffres = <PIPE>;
                   2825:                 close(PIPE);
                   2826:                 chomp($diffres);
                   2827:                 if ($diffres) {
                   2828:                     copy("$apache2_mods_available_dir/status.conf","$apache2_mods_available_dir/status.conf.original");
                   2829:                 } else {
                   2830:                     $skipstatus = 1;
                   2831:                 }
                   2832:             }
                   2833:         }
                   2834:         unless ($skipstatus) {
                   2835:             if (-e $stdstatus) {
                   2836:                 print_and_log(&mt('Copying loncapa [_1] file to [_2],',"'status.conf'","'/etc/apache2/mods-available/status.conf'")."\n");
                   2837:                 copy($stdstatus,$sitestatus);
                   2838:                 chmod(0644,$sitestatus);
                   2839:             }
                   2840:         }
1.28      raeburn  2841:     }
1.1       raeburn  2842:     print_and_log("\n");
                   2843: }
                   2844: 
                   2845: ###########################################################
                   2846: ##
                   2847: ## openSuSE/SLES Copy apache2 config files:
                   2848: ##   default-server.conf, uid.conf, /etc/sysconfig/apache2 
                   2849: ##   and create symlink from /srv/www/conf to /etc/apache2 
                   2850: ##
                   2851: ###########################################################
                   2852: 
                   2853: sub copy_apache2_suseconf {
1.45.2.1  raeburn  2854:     my ($instdir,$distro) = @_;
                   2855:     my ($name,$version) = ($distro =~ /^(suse|sles)([\d\.]+)$/);
                   2856:     my $conf_file = "$instdir/sles-suse/default-server.conf";
                   2857:     if (($name eq 'sles') && ($version >= 12)) {
                   2858:         $conf_file = "$instdir/sles-suse/apache2.4/default-server.conf";
                   2859:     }
1.1       raeburn  2860:     print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',
                   2861:                   "'default-server.conf'",
                   2862:                   "'/etc/apache2/default-server.conf'")."\n");
                   2863:     if (!-e "/etc/apache2/default-server.conf.original") {
                   2864:         copy "/etc/apache2/default-server.conf","/etc/apache2/default-server.conf.original";
                   2865:     }
1.45.2.1  raeburn  2866:     copy $conf_file,"/etc/apache2/default-server.conf";
1.5       raeburn  2867:     chmod(0444,"/etc/apache2/default-server.conf");
1.1       raeburn  2868:     # Make symlink for conf directory (included in loncapa_apache.conf)
                   2869:     my $can_symlink = (eval { symlink('/etc/apache2','/srv/www/conf'); }, $@ eq '');
                   2870:     if ($can_symlink) {
                   2871:         &print_and_log(&mt('Symlink created for [_1] to [_2].',
                   2872:                        "'/srv/www/conf'","'/etc/apache2'")."\n");
                   2873:     } else {
                   2874:         &print_and_log(&mt('Symlink creation failed for [_1] to [_2]. You will need to perform this action from the command line.',"'/srv/www/conf'","'/etc/apache2'")."\n");
                   2875:     }
                   2876:     &copy_apache2_conf_files($instdir);
1.45.2.1  raeburn  2877:     &copy_sysconfig_apache2_file($instdir,$name,$version); 
1.1       raeburn  2878:     print_and_log("\n");
                   2879: }
                   2880: 
                   2881: ###############################################
                   2882: ##
                   2883: ## Modify uid.conf
                   2884: ##
                   2885: ###############################################
                   2886: sub copy_apache2_conf_files {
                   2887:     my ($instdir) = @_;
                   2888:     print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',
                   2889:                   "'uid.conf'","'/etc/apache2/uid.conf'")."\n");
                   2890:     if (!-e "/etc/apache2/uid.conf.original") {
                   2891:         copy "/etc/apache2/uid.conf","/etc/apache2/uid.conf.original";
                   2892:     }
1.9       raeburn  2893:     copy "$instdir/sles-suse/uid.conf","/etc/apache2/uid.conf";
1.5       raeburn  2894:     chmod(0444,"/etc/apache2/uid.conf");
1.1       raeburn  2895: }
                   2896: 
                   2897: ###############################################
                   2898: ##
                   2899: ## Modify /etc/sysconfig/apache2  
                   2900: ##
                   2901: ###############################################
                   2902: sub copy_sysconfig_apache2_file {
1.45.2.1  raeburn  2903:     my ($instdir,$name,$version) = @_;
1.1       raeburn  2904:     print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',"'sysconfig/apache2'","'/etc/sysconfig/apache2'")."\n");
                   2905:     if (!-e "/etc/sysconfig/apache2.original") {
                   2906:         copy "/etc/sysconfig/apache2","/etc/sysconfig/apache2.original";
                   2907:     }
1.45.2.1  raeburn  2908:     my $sysconf_file = "$instdir/sles-suse/sysconfig_apache2";
                   2909:     if (($name eq 'sles') && ($version >= 12)) {
                   2910:        $sysconf_file = "$instdir/sles-suse/apache2.4/sysconfig_apache2";
                   2911:     }
                   2912:     copy $sysconf_file,"/etc/sysconfig/apache2";
1.5       raeburn  2913:     chmod(0444,"/etc/sysconfig/apache2");
1.1       raeburn  2914: }
                   2915: 
                   2916: ###############################################
                   2917: ##
                   2918: ## Add/Modify /etc/insserv/overrides
                   2919: ##
                   2920: ###############################################
                   2921: 
                   2922: sub update_SuSEfirewall2_setup {
                   2923:     my ($instdir) = @_;
                   2924:     print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',"'SuSEfirewall2_setup'","'/etc/insserv/overrides/SuSEfirewall2_setup'")."\n");
                   2925:     if (!-e "/etc/insserv/overrides/SuSEfirewall2_setup") {
                   2926:         if (!-d "/etc/insserv") {
                   2927:             mkdir("/etc/insserv",0755); 
                   2928:         }
                   2929:         if (!-d "/etc/insserv/overrides") {
                   2930:             mkdir("/etc/insserv/overrides",0755);
                   2931:         }
                   2932:     } elsif (!-e  "/etc/insserv/overrides/SuSEfirewall2_setup.original") {
                   2933:         copy "/etc/insserv/overrides/SuSEfirewall2_setup","/etc/insserv/overrides/SuSEfirewall2_setup.original"
                   2934:     }
1.9       raeburn  2935:     copy "$instdir/sles-suse/SuSEfirewall2_setup","/etc/insserv/overrides/SuSEfirewall2_setup";
1.5       raeburn  2936:     chmod(0444,"/etc/insserv/overrides/SuSEfirewall2_setup");
                   2937: }
                   2938: 
                   2939: sub get_iptables_rules {
                   2940:     my ($distro,$instdir,$apachefw) = @_;
                   2941:     my (@fwchains,@ports);
                   2942:     if (&firewall_is_active()) {
                   2943:         my $iptables = &get_pathto_iptables();
                   2944:         if ($iptables ne '') {
                   2945:             @fwchains = &get_fw_chains($iptables,$distro);
                   2946:         }
                   2947:     }
                   2948:     if (ref($apachefw) eq 'HASH') {
                   2949:         foreach my $service ('http','https') {
                   2950:             unless ($apachefw->{$service}) {
                   2951:                 push (@ports,$service); 
                   2952:             }
                   2953:         }
                   2954:     } else {
                   2955:         @ports = ('http','https');
                   2956:     }
                   2957:     if (@ports == 0) {
                   2958:         return;
                   2959:     }
                   2960:     my $ask_to_enable;
                   2961:     if (-e "/etc/iptables.loncapa.rules") {
1.9       raeburn  2962:         if (open(PIPE, "diff --brief $instdir/debian-ubuntu/iptables.loncapa.rules /etc/iptables.loncapa.rules |")) {
1.5       raeburn  2963:             my $diffres = <PIPE>;
                   2964:             close(PIPE);
                   2965:             chomp($diffres);
                   2966:             if ($diffres) {
                   2967:                 print &mt('Warning: [_1] exists but differs from LON-CAPA supplied file.','/etc/iptables.loncapa.rules')."\n";
                   2968:             }
                   2969:         } else {
                   2970:             print &mt('Error: unable to open [_1] to compare contents with LON-CAPA supplied file.','/etc/iptables.loncapa.rules')."\n";
                   2971:         }
                   2972:     } else {
1.9       raeburn  2973:         if (-e "$instdir/debian-ubuntu/iptables.loncapa.rules") {
                   2974:             copy "$instdir/debian-ubuntu/iptables.loncapa.rules","/etc/iptables.loncapa.rules";
1.5       raeburn  2975:             chmod(0600,"/etc/iptables.loncapa.rules");
                   2976:         }
                   2977:     }
                   2978:     if (-e "/etc/iptables.loncapa.rules") {
                   2979:         if (-e "/etc/network/if-pre-up.d/iptables") {
1.9       raeburn  2980:             if (open(PIPE, "diff --brief $instdir/debian-ubuntu/iptables /etc/network/if-pre-up/iptables |")) {
1.5       raeburn  2981:                 my $diffres = <PIPE>;
                   2982:                 close(PIPE);
                   2983:                 chomp($diffres);
                   2984:                 if ($diffres) {
                   2985:                     print &mt('Warning: [_1] exists but differs from LON-CAPA supplied file.','/etc/network/if-pre-up.d/iptables')."\n";
                   2986:                 }
                   2987:             } else {
                   2988:                 print &mt('Error: unable to open [_1] to compare contents with LON-CAPA supplied file.','/etc/network/if-pre-up.d/iptables')."\n";
                   2989:             }
                   2990:         } else {
1.9       raeburn  2991:             copy "$instdir/debian-ubuntu/iptables","/etc/network/if-pre-up.d/iptables";
1.5       raeburn  2992:             chmod(0755,"/etc/network/if-pre-up.d/iptables");
                   2993:             print_and_log(&mt('Installed script "[_1]" to add iptables rules to block all ports except 22, 80, and 443 when network is enabled during boot.','/etc/network/if-pre-up.d/iptables'));
                   2994:             $ask_to_enable = 1;
                   2995:         }
                   2996:     }
                   2997:     return $ask_to_enable;
1.1       raeburn  2998: }
                   2999: 
                   3000: sub download_loncapa {
                   3001:     my ($instdir,$lctarball) = @_;
                   3002:     my ($have_tarball,$updateshown);
                   3003:     if (! -e "$instdir/$lctarball") {
                   3004: 	print_and_log(&mt('Retrieving LON-CAPA source files from: [_1]',
                   3005: 		      'http://install.loncapa.org')."\n");
                   3006: 	system("wget http://install.loncapa.org/versions/$lctarball ".
                   3007: 	       "2>/dev/null 1>/dev/null");
                   3008: 	if (! -e "./$lctarball") {
                   3009: 	    print &mt('Unable to retrieve LON-CAPA source files from: [_1].', 
                   3010: 		     "http://install.loncapa.org/versions/$lctarball")."\n";
                   3011: 	} else {
                   3012:             $have_tarball = 1;
                   3013:         }
                   3014: 	print_and_log("\n");
                   3015:     } else {
                   3016:         $have_tarball = 1;
                   3017: 	print_and_log("
                   3018: ------------------------------------------------------------------------
                   3019: 
1.45.2.16  raeburn  3020: ".&mt('You seem to have a version of [_1] in [_2]',$lctarball,$instdir)."\n".
1.1       raeburn  3021: &mt('This copy will be used and a new version will NOT be downloaded.')."\n".
                   3022: &mt('If you wish, you may download a new version by executing:')."
                   3023: 
1.45.2.16  raeburn  3024: wget http://install.loncapa.org/versions/$lctarball
1.1       raeburn  3025: 
                   3026: ------------------------------------------------------------------------
                   3027: ");
                   3028:     }
                   3029: 
                   3030:     ##
1.45.2.16  raeburn  3031:     ## untar loncapa-X.Y.Z.tar.gz
1.1       raeburn  3032:     ##
                   3033:     if ($have_tarball) {
1.45.2.16  raeburn  3034:         my $homedir = '/root';
                   3035:         my ($targetdir,$chdircmd,$updatecmd);
                   3036:         if (($distro =~ /^ubuntu/) && ($instdir ne $homedir)) {
                   3037:             ($homedir) = ($instdir =~ m{^(.*)/[^/]+$});
                   3038:             $updatecmd = 'sudo ./UPDATE';
                   3039:         } else {
                   3040:             $updatecmd = './UPDATE';
                   3041:         }
1.1       raeburn  3042:         print_and_log(&mt('Extracting LON-CAPA source files')."\n");
1.45.2.16  raeburn  3043:         if (-e $homedir) {
                   3044:             writelog(`tar zxf $instdir/$lctarball --directory $homedir`);
                   3045:             $targetdir = $homedir;
                   3046:         } else {
                   3047:             writelog(`tar zxf $instdir/$lctarball`);
                   3048:             $targetdir = $instdir;
                   3049:         }
                   3050:         if ($lctarball =~ /^loncapa\-(\d+\.\d+\.\d+(?:|[^.]+))\.tar\.gz$/) {
                   3051:             $chdircmd = "cd $targetdir/loncapa-".$1;
                   3052:         } else {
                   3053:             $chdircmd = "cd $targetdir/loncapa-X.Y.Z  (X.Y.Z should correspond to a version number like '2.11.3')";
                   3054:         }
1.1       raeburn  3055:         print_and_log("\n");
                   3056:         print &mt('LON-CAPA source files extracted.')."\n".
1.45.2.16  raeburn  3057:               &mt('It remains for you to execute the following commands:').
                   3058:               "\n$chdircmd\n$updatecmd\n".
                   3059:               &mt('If you have any trouble, please see [_1] and [_2]',
                   3060:                   'http://install.loncapa.org/','http://help.loncapa.org/')."\n";
1.1       raeburn  3061:         $updateshown = 1;
                   3062:     }
                   3063:     return ($have_tarball,$updateshown);
                   3064: }
                   3065: 
                   3066: close LOG;

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