--- doc/install/linux/install.pl 2021/12/10 15:31:47 1.45.2.17 +++ doc/install/linux/install.pl 2024/08/01 12:57:23 1.45.2.22 @@ -76,7 +76,7 @@ if (!open(LOG,">>loncapa_install.log")) &mt('Stopping execution.')."\n"; exit; } else { - print LOG '$Id: install.pl,v 1.45.2.17 2021/12/10 15:31:47 raeburn Exp $'."\n"; + print LOG '$Id: install.pl,v 1.45.2.22 2024/08/01 12:57:23 raeburn Exp $'."\n"; } # @@ -210,8 +210,11 @@ sub get_distro { $distro = 'rhes'.$1; $updatecmd = 'dnf install LONCAPA-prerequisites'; $installnow = 'dnf -y install LONCAPA-prerequisites'; - } elsif ($versionstring =~ /CentOS(?:| Linux| Stream) release (\d+)/) { - $distro = 'centos'.$1; + } elsif ($versionstring =~ /CentOS(| Linux| Stream) release (\d+)/) { + $distro = 'centos'.$2; + if ($1 eq ' Stream') { + $distro .= '-stream'; + } $updatecmd = 'yum install LONCAPA-prerequisites'; $installnow = 'yum -y install LONCAPA-prerequisites'; } elsif ($versionstring =~ /Scientific Linux (?:SL )?release ([\d.]+) /) { @@ -220,6 +223,18 @@ sub get_distro { $distro = 'scientific'.$ver; $updatecmd = 'yum install LONCAPA-prerequisites'; $installnow = 'yum -y install LONCAPA-prerequisites'; + } elsif ($versionstring =~ /Rocky Linux release ([\d.]+)/) { + my $ver = $1; + $ver =~ s/\.\d+$//; + $distro = 'rocky'.$ver; + $updatecmd = 'dnf install LONCAPA-prerequisites'; + $installnow = 'dnf -y install LONCAPA-prerequisites'; + } elsif ($versionstring =~ /AlmaLinux release ([\d.]+) /) { + my $ver = $1; + $ver =~ s/\.\d+$//; + $distro = 'alma'.$ver; + $updatecmd = 'dnf install LONCAPA-prerequisites'; + $installnow = 'dnf -y install LONCAPA-prerequisites'; } else { print &mt('Unable to interpret [_1] to determine system type.', '/etc/redhat-release')."\n"; @@ -358,7 +373,7 @@ sub check_prerequisites { sub check_locale { my ($distro) = @_; - my ($fh,$langvar,$command,$earlyout); + my ($fh,$langvar,$command,$langcmd,$earlyout,$default); $langvar = 'LANG'; if ($distro =~ /^(ubuntu|debian)/) { if (!open($fh,"= 7) { if (!open($fh,"; chomp(@data); + close($fh); foreach my $item (@data) { if ($item =~ /^\Q$langvar\E=\"?([^\"]*)\"?/) { - my $default = $1; + $default = $1; if ($default ne 'en_US.UTF-8') { if ($distro =~ /^debian/) { $command = 'locale-gen en_US.UTF-8'."\n". @@ -438,8 +454,72 @@ sub check_locale { last; } } - close($fh); - return $command; +# Check for locales + if ($default ne 'en_US.UTF-8') { + my ($has_us_english,$has_other_code,$has_other_lang); + if (open(PIPE,"locale -a 2>/dev/null |")) { + while () { + chomp(); + next if (/^(C(|\.utf8)|POSIX)$/i); + if (/^en_US\.utf8/i) { + $has_us_english = 1; + } elsif (/^[A-Za-z]{2}_[A-Za-z]{2}/) { + $has_other_code = 1; + } elsif (/^[A-Za-z]{3,}/) { + $has_other_lang = 1; + } + } + close(PIPE); + if (!$has_us_english) { + if ($has_other_code || $has_other_lang) { + if ($distro =~ /^ubuntu/) { + $langcmd = "sudo apt-get install language-pack-en\n"; + } elsif ($distro =~ /^debian/) { + $langcmd = "apt-get install language-pack-en\n"; + } elsif ($distro =~ /^(suse|sles)/) { + $langcmd = &mt('Use yast: System > Language > Primary Language = English')."\n"; + } elsif ($distro =~ /^fedora(\d+)$/) { + if ($1 > 23) { + $langcmd = "dnf install glibc-langpack-en\n"; + } else { + $langcmd = "yum install glibc-common\n"; + } + } elsif ($distro =~ /^(?:rhes|centos|scientific|oracle|rocky|alma)(\d+)/) { + if ($1 > 7) { + $langcmd = "dnf install glibc-langpack-en\n"; + } else { + $langcmd = "yum install glibc-common\n"; + } + } + } else { + if ($distro =~ /^ubuntu/) { + $langcmd = "sudo apt-get install language-pack-en\n"; + } elsif ($distro =~ /^debian/) { + $langcmd = "apt-get install language-pack-en\n"; + } elsif ($distro =~ /^(suse|sles)/) { + $langcmd = &mt('Use yast: System > Language > Primary Language = English')."\n"; + } elsif ($distro =~ /^fedora(\d+)$/) { + if ($1 > 23) { + $langcmd = &mt('Either install all languages[_1]or install English only[_2]', + ":\ndnf install glibc-all-langpacks\n\n", + ":\ndnf install glibc-langpack-en\n"); + } else { + $langcmd = "yum install glibc-common\n"; + } + } elsif ($distro =~ /^(?:rhes|centos|scientific|oracle|rocky|alma)(\d+)/) { + if ($1 > 7) { + $langcmd = &mt('Either install all languages[_1]or install English only[_2]', + ":\ndnf install glibc-all-langpacks\n\n", + ":\ndnf install glibc-langpack-en\n"); + } else { + $langcmd = "yum install glibc-common\n"; + } + } + } + } + } + } + return ($command,$langcmd); } sub check_required { @@ -450,11 +530,11 @@ sub check_required { } my $gotprereqs = &check_prerequisites($packagecmd,$distro); if ($gotprereqs eq '') { - return ($distro,$gotprereqs,'',$packagecmd,$updatecmd); + return ($distro,$gotprereqs,'','',$packagecmd,$updatecmd); } - my $localecmd = &check_locale($distro); + my ($localecmd,$langcmd) = &check_locale($distro); unless ($localecmd eq '') { - return ($distro,$gotprereqs,$localecmd); + return ($distro,$gotprereqs,$localecmd,$langcmd); } my ($mysqlon,$mysqlsetup,$mysqlrestart,$dbh,$has_pass,$mysql_unix_socket,$has_lcdb, %recommended,$downloadstatus,$filetouse,$production,$testing,$apachefw, @@ -474,10 +554,10 @@ sub check_required { if ($mysqlsetup eq 'needsrestart') { $mysqlrestart = ''; if ($distro eq 'ubuntu') { - $mysqlrestart = 'sudo '; + $mysqlrestart = 'sudo '; } $mysqlrestart .= 'service mysql restart'; - return ($distro,$gotprereqs,$localecmd,$packagecmd,$updatecmd,$installnow,$mysqlrestart); + return ($distro,$gotprereqs,$localecmd,$langcmd,$packagecmd,$updatecmd,$installnow,$mysqlrestart); } else { if ($mysqlsetup eq 'noroot') { $recommended{'mysqlperms'} = 1; @@ -496,11 +576,14 @@ sub check_required { } ($recommended{'firewall'},$apachefw) = &chkfirewall($distro); ($recommended{'runlevels'},$tostop,$uses_systemctl) = &chkconfig($distro,$instdir); + if ((ref($uses_systemctl) eq 'HASH') && ($uses_systemctl->{'apache'})) { + $recommended{'systemd'} = &check_systemd_security($distro); + } $recommended{'apache'} = &chkapache($distro,$instdir); $recommended{'stopsrvcs'} = &chksrvcs($distro,$tostop); ($recommended{'download'},$downloadstatus,$filetouse,$production,$testing) = &need_download($distro,$instdir); - return ($distro,$gotprereqs,$localecmd,$packagecmd,$updatecmd,$installnow, + return ($distro,$gotprereqs,$localecmd,$langcmd,$packagecmd,$updatecmd,$installnow, $mysqlrestart,\%recommended,$dbh,$has_pass,$mysql_unix_socket, $has_lcdb,$downloadstatus,$filetouse,$production,$testing,$apachefw, $uses_systemctl); @@ -520,6 +603,20 @@ sub check_mysql_running { $process = 'mysqld'; $proc_owner = 'mysql'; } + if ($1 >= 16) { + $use_systemctl = 1; + } + } elsif ($distro =~ /^debian(\w+)/) { + if ($1 >= 10) { + $process = 'mysql'; + $proc_owner = 'mysql'; + } + if ($1 >= 11) { + $mysqldaemon = 'mariadb'; + } + if ($1 >= 9) { + $use_systemctl = 1; + } } elsif ($distro =~ /^fedora(\d+)/) { if ($1 >= 16) { $process = 'mysqld'; @@ -532,13 +629,16 @@ sub check_mysql_running { if ($1 >= 34) { $process = 'mariadb'; } - } elsif ($distro =~ /^(?:centos|rhes|scientific|oracle)(\d+)/) { + } elsif ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) { if ($1 >= 7) { $mysqldaemon ='mariadb'; $process = 'mysqld'; $proc_owner = 'mysql'; $use_systemctl = 1; } + if ($1 >= 9) { + $process = 'mariadb'; + } } elsif ($distro =~ /^sles(\d+)/) { if ($1 >= 12) { $use_systemctl = 1; @@ -659,9 +759,13 @@ sub chkconfig { if (($distro =~ /^ubuntu/) && ($version <= 8)) { $daemon{'cups'} = 'cupsys'; } - if (($distro =~ /^ubuntu/) && ($version >= 18)) { + if ((($distro =~ /^ubuntu/) && ($version >= 18)) || + (($distro =~ /^debian/) && ($version >= 10))) { $daemon{'ntp'} = 'chrony'; } + if (($distro =~ /^debian/) && ($version >= 11)) { + $daemon{'mysql'} = 'mariadb'; + } } elsif ($distro =~ /^fedora(\d+)/) { my $version = $1; if ($version >= 15) { @@ -679,7 +783,7 @@ sub chkconfig { if ($version >= 26) { $daemon{'ntp'} = 'chronyd'; } - } elsif ($distro =~ /^(?:centos|rhes|scientific|oracle)(\d+)/) { + } elsif ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) { my $version = $1; if ($version >= 7) { $uses_systemctl{'ntp'} = 1; @@ -784,6 +888,26 @@ sub chkconfig { return (\%needfix,\%tostop,\%uses_systemctl); } +sub check_systemd_security { + my ($distro) = @_; + my $service = 'httpd.service'; + if ($distro =~ /^(suse|sles|ubuntu|debian)/) { + $service = 'apache2.service'; + } + system("systemctl daemon-reload"); + if (open(PIPE,"systemctl show $service --property=ProtectHome 2>/dev/null |")) { + my $protection = ; + close(PIPE); + chomp($protection); + if ($protection =~ /^ProtectHome=(read-only|yes)$/i) { + return 1; + } + } else { + print &mt('Could not check systemctl configuration for Apache')."\n"; + } + return 0; +} + sub uses_firewalld { my ($distro) = @_; my ($inuse,$checkfirewalld,$zone); @@ -795,7 +919,7 @@ sub uses_firewalld { if ($1 >= 18) { $checkfirewalld = 1; } - } elsif ($distro =~ /^(?:centos|rhes|scientific|oracle)(\d+)/) { + } elsif ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) { if ($1 >= 7) { $checkfirewalld = 1; } @@ -887,7 +1011,8 @@ sub chkapache { my $distname = $1; my $version = $2; my ($stdconf,$stdsite); - if (($distname eq 'ubuntu') && ($version > 12)) { + if ((($distname eq 'ubuntu') && ($version > 12)) || + (($distname eq 'debian') && ($version >= 10))) { $stdconf = "$instdir/debian-ubuntu/ubuntu14/loncapa_conf"; $stdsite = "$instdir/debian-ubuntu/ubuntu14/loncapa_sites"; } else { @@ -898,7 +1023,8 @@ sub chkapache { print &mt('Warning: No LON-CAPA Apache configuration file found for installation check.')."\n"; } else { my ($configfile,$sitefile); - if (($distname eq 'ubuntu') && ($version > 12)) { + if ((($distname eq 'ubuntu') && ($version > 12)) || + (($distname eq 'debian') && ($version >= 10))) { $sitefile = '/etc/apache2/sites-available/loncapa.conf'; $configfile = '/etc/apache2/conf-available/loncapa.conf'; } else { @@ -914,13 +1040,16 @@ sub chkapache { } } } - if ((!$fixapache) && ($distname eq 'ubuntu') && ($version > 12)) { + if ((!$fixapache) && ((($distname eq 'ubuntu') && ($version > 12)) || + (($distname eq 'debian') && ($version >= 10)))) { if (($sitefile ne '') && (-e $sitefile) && (-e $stdsite)) { if (open(PIPE, "diff --brief $stdsite $sitefile |")) { my $diffres = ; close(PIPE); chomp($diffres); - unless ($diffres) { + if ($diffres) { + $fixapache = 1; + } else { $fixapache = 0; } } @@ -934,7 +1063,7 @@ sub chkapache { } } } - if ((!$fixapache) && ($distname eq 'ubuntu')) { + if ((!$fixapache) && (($distname eq 'ubuntu') || ($distname eq 'debian'))) { my $sitestatus = "/etc/apache2/mods-available/status.conf"; my $stdstatus = "$instdir/debian-ubuntu/status.conf"; if ((-e $stdstatus) && (-e $sitestatus)) { @@ -988,7 +1117,7 @@ sub chkapache { } else { my $configfile = 'httpd.conf'; my $mpmfile = 'mpm.conf'; - if ($distro =~ /^(?:centos|rhes|scientific|oracle)(\d+)$/) { + if ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) { if ($1 >= 7) { $configfile = 'apache2.4/httpd.conf'; } elsif ($1 > 5) { @@ -1160,8 +1289,8 @@ sub check_mysql_setup { my ($instdir,$dsn,$distro) = @_; my ($mysqlsetup,$has_pass,$mysql_unix_socket,$mysql_has_wwwuser); my $dbh = DBI->connect($dsn,'root','',{'PrintError'=>0}); - my ($mysqlversion,$mysqlsubver,$mysqlname) = &get_mysql_version(); - if (($mysqlname =~ /^MariaDB/i) && ($mysqlversion >= 10.4)) { + my ($mysqlversion,$mysqlminorversion,$mysqlsubver,$mysqlname) = &get_mysql_version(); + if (($mysqlname =~ /^MariaDB/i) && (($mysqlversion == 10 && $mysqlminorversion >= 4) || ($mysqlversion >= 11))) { if ($dbh) { my $sth = $dbh->prepare("SELECT Priv FROM mysql.global_priv WHERE (User = 'root' AND Host ='localhost')"); $sth->execute(); @@ -1182,7 +1311,7 @@ sub check_mysql_setup { } if ($dbh) { $mysqlsetup = 'noroot'; - if (($mysqlname !~ /^MariaDB/i) && ($mysqlversion >= 5.7)) { + if (($mysqlname !~ /^MariaDB/i) && (($mysqlversion == 5 && $mysqlminorversion >= 7) || ($mysqlversion >= 6))) { my $sth = $dbh->prepare("SELECT plugin from mysql.user where User='root'"); $sth->execute(); while (my $priv = $sth->fetchrow_array) { @@ -1307,14 +1436,30 @@ sub get_pathto_iptables { sub firewall_is_active { if (-e '/proc/net/ip_tables_names') { + my $status; if (open(PIPE,'cat /proc/net/ip_tables_names |grep filter |')) { - my $status = ; + $status = ; close(PIPE); chomp($status); if ($status eq 'filter') { return 1; } } + unless ($status) { + if (open(PIPE,'nft list tables |')) { + while() { + chomp(); + if (/filter$/) { + $status = 1; + last; + } + } + close(PIPE); + if ($status) { + return 1; + } + } + } } return 0; } @@ -1476,11 +1621,12 @@ print " ".&mt('3.')." ".&mt('Set-up the MySQL database.')." ".&mt('4.')." ".&mt('Set-up MySQL permissions.')." ".&mt('5.')." ".&mt('Configure Apache web server.')." -".&mt('6.')." ".&mt('Configure start-up of services.')." -".&mt('7.')." ".&mt('Check firewall settings.')." -".&mt('8.')." ".&mt('Stop services not used by LON-CAPA,')." +".&mt('6.')." ".&mt('Configure systemd security settings for Apache web server.')." +".&mt('7.')." ".&mt('Configure start-up of services.')." +".&mt('8.')." ".&mt('Check firewall settings.')." +".&mt('9.')." ".&mt('Stop services not used by LON-CAPA,')." ".&mt('i.e., services for a print server: [_1] daemon.',"'cups'")." -".&mt('9.')." ".&mt('Download LON-CAPA source code in readiness for installation.')." +".&mt('10.')." ".&mt('Download LON-CAPA source code in readiness for installation.')." ".&mt('Typically, you will run this script only once, when you first install LON-CAPA.')." @@ -1509,7 +1655,7 @@ my $instdir = `pwd`; chomp($instdir); my %callsub; -my @actions = ('wwwuser','pwauth','mysql','mysqlperms','apache', +my @actions = ('wwwuser','pwauth','mysql','mysqlperms','apache','systemd', 'runlevels','firewall','stopsrvcs','download'); my %prompts = &texthash( wwwuser => "Create the 'www' user?", @@ -1517,6 +1663,7 @@ my %prompts = &texthash( mysql => 'Set-up the MySQL database?', mysqlperms => 'Set-up MySQL permissions?', apache => 'Configure Apache web server?', + systemd => 'Configure systemd security settings for Apache web server?', runlevels => 'Set overrides for start-up order of services?', firewall => 'Configure firewall settings for Apache', stopsrvcs => 'Stop extra services not required on a LON-CAPA server?', @@ -1526,7 +1673,7 @@ my %prompts = &texthash( print "\n".&mt('Checking system status ...')."\n"; my $dsn = "DBI:mysql:database=mysql"; -my ($distro,$gotprereqs,$localecmd,$packagecmd,$updatecmd,$installnow,$mysqlrestart, +my ($distro,$gotprereqs,$localecmd,$langcmd,$packagecmd,$updatecmd,$installnow,$mysqlrestart, $recommended,$dbh,$has_pass,$mysql_unix_socket,$has_lcdb,$downloadstatus, $filetouse,$production,$testing,$apachefw,$uses_systemctl) = &check_required($instdir,$dsn); if ($distro eq '') { @@ -1545,8 +1692,12 @@ if ($mysqlrestart) { exit; } if ($localecmd ne '') { - 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"; - 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". + print "\n".&mt('Although the LON-CAPA application itself is localized for a number of different languages,[_1]the default locale language for the Linux OS on which it runs should be US English.',"\n")."\n\n"; + if ($langcmd ne '') { + print &mt('Use the following command(s) or action(s) to install a required language package.')."\n\n". + "$langcmd\n"; + } + print &mt('Run the following command from the command line to set the default language for your OS,[_1]and then run this LON-CAPA installation set-up script again.',"\n")."\n\n". $localecmd."\n\n". &mt('Stopping execution.')."\n"; exit; @@ -1570,7 +1721,7 @@ if (!$gotprereqs) { &mt('Stopping execution.')."\n"; exit; } else { - ($distro,$gotprereqs,$localecmd,$packagecmd,$updatecmd,$installnow, + ($distro,$gotprereqs,$localecmd,$langcmd,$packagecmd,$updatecmd,$installnow, $mysqlrestart,$recommended,$dbh,$has_pass,$mysql_unix_socket, $has_lcdb,$downloadstatus,$filetouse,$production,$testing,$apachefw, $uses_systemctl) = &check_required($instdir,$dsn); @@ -1723,6 +1874,12 @@ if ($callsub{'apache'}) { print_and_log(&mt('Skipping configuration of Apache web server.')."\n"); } +if ($callsub{'systemd'}) { + &check_systemd_update($distro); +} else { + print_and_log('Skipping systemd configuration update for web server'); +} + if ($callsub{'runlevels'}) { my $count = 0; if (ref($recommended) eq 'HASH') { @@ -1810,7 +1967,7 @@ if ($callsub{'firewall'}) { 'ssh, http')."\n"; } else { my $version; - if ($distro =~ /^(redhat|centos)(\d+)$/) { + if ($distro =~ /^(redhat|centos|rocky|alma)(\d+)/) { $version = $1; } if ($version > 5) { @@ -1841,10 +1998,11 @@ if ($callsub{'download'}) { print &mt('LON-CAPA is available for download from: [_1]', 'http://install.loncapa.org/')."\n"; if (!-e '/etc/loncapa-release') { - &print_and_log(&mt('LON-CAPA is not yet installed on your system.'). - "\n\n". - &mt('You may retrieve the source for LON-CAPA by executing:')."\n". - "wget http://install.loncapa.org/versions/$lctarball\n"); + &print_and_log(&mt('LON-CAPA is not yet installed on your system.')."\n\n"); + unless ($filetouse) { + &print_and_log(&mt('You may retrieve the source for LON-CAPA by executing:')."\n". + "wget http://install.loncapa.org/versions/$lctarball\n"); + } } else { my $currentversion; if (open(my $fh," 6) { $lc_uses_systemctl = 1; } - } elsif ($distro =~ /^(?:rhes|centos)(\d+)$/) { + } elsif ($distro =~ /^(?:rhes|centos|rocky|alma)(\d+)/) { if ($1 > 7) { $lc_uses_systemctl = 1; } @@ -1899,10 +2057,18 @@ if ($have_tarball && !$updateshown) { $lc_uses_systemctl = 1; } $uses_sudo = 1; + } elsif ($distro =~ /^debian(\d+)$/) { + if ($1 >= 10) { + $lc_uses_systemctl = 1; + } } elsif ($distro =~ /^sles(\d+)$/) { if ($1 > 12) { $lc_uses_systemctl = 1; } + } elsif ($distro =~ /^fedora(\d+)$/) { + if ($1 > 25) { + $lc_uses_systemctl = 1; + } } if (!-e '/etc/loncapa-release') { print &mt('If you are now ready to install LON-CAPA, enter the following commands:')."\n\n"; @@ -1937,7 +2103,7 @@ if ($have_tarball && !$updateshown) { "cd $homedir/$lcdir\n". "$update\n"; if (-e '/etc/loncapa-release') { - my $lcstart = '/etc/init.d/loncontrol start'; + my $lcstart = '/etc/init.d/loncontrol start'; if ($lc_uses_systemctl) { $lcstart = '/home/httpd/perl/loncontrol start'; } @@ -2019,6 +2185,29 @@ sub build_and_install_mod_auth_external > #define SERVER_UIDS $num /* user "www" */ ENDPATCH + my $patch_code = <<"ENDPATCH"; +127a128 +> #include +214a216 +> #include +566c568 +< check_fails() +--- +> int check_fails() +589c591 +< log_failure() +--- +> void log_failure() +629c631 +< snooze(int seconds) +--- +> void snooze(int seconds) +653c655 +< main(int argc, char **argv) +--- +> int main(int argc, char **argv) +ENDPATCH + if (! -e "/usr/bin/patch") { print_and_log(&mt('You must install the software development tools package: [_1], when installing Linux.',"'patch'")."\n"); print_and_log(&mt('Authentication installation not completed.')."\n"); @@ -2029,9 +2218,17 @@ ENDPATCH return; } my $dir = "/tmp/pwauth-2.2.8"; + my $patchedok; if (open(PATCH,"| patch $dir/config.h")) { print PATCH $patch; close(PATCH); + if (open(PATCH,"| patch $dir/pwauth.c")) { + print PATCH $patch_code; + close(PATCH); + $patchedok = 1; + } + } + if ($patchedok) { print_and_log("\n"); ## ## Compile patched pwauth @@ -2102,7 +2299,8 @@ sub kill_extra_services { &print_and_log(&mt('Removing [_1] from startup.',$service)."\n"); if ($distro =~ /^(?:debian|ubuntu)(\d+)/) { my $version = $1; - if (($distro =~ /^ubuntu/) && ($version > 16)) { + if ((($distro =~ /^ubuntu/) && ($version > 16)) || + (($distro =~ /^debian/) && ($version >= 10))) { if (ref($uses_systemctl) eq 'HASH') { if ($uses_systemctl->{$service}) { if (`systemctl is-enabled $service`) { @@ -2172,21 +2370,23 @@ CREATE TABLE IF NOT EXISTS metadata (tit sub setup_mysql_permissions { my ($dbh,$has_pass,$mysql_unix_socket,@mysql_lc_commands) = @_; - my ($mysqlversion,$mysqlsubver,$mysqlname) = &get_mysql_version(); + my ($mysqlversion,$mysqlminorversion,$mysqlsubver,$mysqlname) = &get_mysql_version(); my ($usescreate,$usesauth,$is_mariadb,$hasauthcol,@mysql_commands); if ($mysqlname =~ /^MariaDB/i) { $is_mariadb = 1; - if ($mysqlversion >= 10.4) { + if ((($mysqlversion == 10) && ($mysqlminorversion >= 4)) || ($mysqlversion >= 11)) { $usescreate = 1; - } elsif ($mysqlversion >= 10.2) { + } elsif (($mysqlversion == 10) && ($mysqlminorversion >= 2)) { $usesauth = 1; - } elsif ($mysqlversion >= 5.5) { + } elsif (($mysqlversion == 5) && ($mysqlminorversion >= 5)) { $hasauthcol = 1; } } else { - if (($mysqlversion > 5.7) || (($mysqlversion == 5.7) && ($mysqlsubver > 5))) { + if (($mysqlversion > 5) || (($mysqlminorversion == 5) && ($mysqlminorversion > 7)) || + (($mysqlversion == 5) && ($mysqlminorversion == 7) && ($mysqlsubver > 5))) { $usesauth = 1; - } elsif (($mysqlversion >= 5.6) || (($mysqlversion == 5.5) && ($mysqlsubver >= 7))) { + } elsif (($mysqlversion == 5) && + (($mysqlminorversion >= 6) || (($mysqlminorversion == 5) && ($mysqlsubver >= 7)))) { $hasauthcol = 1; } } @@ -2300,17 +2500,129 @@ sub new_mysql_rootpasswd { } sub get_mysql_version { - my ($version,$subversion,$name); + my ($version,$minorversion,$subversion,$name); if (open(PIPE," mysql -V |")) { my $info = ; chomp($info); close(PIPE); - ($version,$subversion,$name) = ($info =~ /(\d+\.\d+)\.(\d+)(?:\-?(\w*),|)/); + ($version,$minorversion,$subversion,$name) = ($info =~ /(\d+)\.(\d+)\.(\d+)(?:\-?(\w*),|)/); } else { print &mt('Could not determine which version of MySQL is installed.'). "\n"; } - return ($version,$subversion,$name); + return ($version,$minorversion,$subversion,$name); +} + +sub check_systemd_update { + my ($distro) = @_; + my ($use_systemctl,$service); + $service = 'apache2.service'; + if ($distro =~ /^ubuntu(\w+)/) { + if ($1 >= 16) { + $use_systemctl = 1; + } + } elsif ($distro =~ /^debian(\w+)/) { + if ($1 >= 9) { + $use_systemctl = 1; + } + } elsif ($distro =~ /^fedora(\d+)/) { + $service = 'httpd.service'; + if ($1 >= 16) { + $use_systemctl = 1; + } + } elsif ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) { + $service = 'httpd.service'; + if ($1 >= 7) { + $use_systemctl = 1; + } + } elsif ($distro =~ /^sles(\d+)/) { + if ($1 >= 12) { + $use_systemctl = 1; + } + } elsif ($distro =~ /^suse(\d+)/) { + if ($1 >= 13) { + $use_systemctl = 1; + } + } + if ($use_systemctl) { + my $needsupdate = &check_systemd_security($distro); + if ($needsupdate) { + if (!-d '/etc/systemd/system/'.$service.'.d') { + mkdir '/etc/systemd/system/'.$service.'.d', 0755; + } + if (-d '/etc/systemd/system/'.$service.'.d') { + if (-e '/etc/systemd/system/'.$service.'.d/override.conf') { + if (open(my $fh,'<','/etc/systemd/system/'.$service.'.d/override.conf')) { + my ($inservice,$addservice,$protectoff,$linenum,$change,@lines); + while (my $entry = <$fh>) { + $linenum ++; + chomp($entry); + if ($entry eq '[Service]') { + if (!$protectoff) { + $inservice = $linenum; + push(@lines,$entry); + } else { + $addservice = 1; + next; + } + } + if ($entry =~ /^ProtectHome\s*=\s*([\w-]+)\s*$/) { + my $value = $1; + if ($protectoff) { + next; + if (lc($value) eq 'no') { + $protectoff = $linenum; + push(@lines,$entry); + } else { + if ($protectoff) { + next; + } else { + push(@lines,'ProtectHome=no'); + $protectoff = $linenum; + $change = $linenum; + } + } + } + } + } + close($fh); + if ($addservice || $change || !$protectoff) { + if (open(my $fh,'>','/etc/systemd/system/'.$service.'.d/override.conf')) { + if ($addservice) { + print $fh "[Service]\n"; + } + foreach my $entry (@lines) { + print $fh "$entry\n"; + } + close($fh); + print_and_log('Updated /etc/systemd/system/'.$service.'.d/override.conf'); + system('systemctl daemon-reload'); + } else { + print_and_log('Could not open /etc/systemd/system/'.$service.'.d/override.conf for writing.'); + } + } else { + print_and_log('No change needed in /etc/systemd/system/'.$service.'.d/override.conf'); + } + } else { + print_and_log('Could not open /etc/systemd/system/'.$service.'.d/override.conf for reading.'); + } + } else { + if (open(my $fh,'>','/etc/systemd/system/'.$service.'.d/override.conf')) { + print $fh '[Service]'."\n".'ProtectHome=no'."\n"; + close($fh); + print_and_log('Created /etc/systemd/system/'.$service.'.d/override.conf'); + system('systemctl daemon-reload'); + } + } + } else { + print_and_log('No /etc/systemd/system/'.$service.'.d directory exists and creating one failed,'); + } + } else { + print_and_log('No update needed to systemd security settings for Apache web server.'); + } + } else { + print_and_log('No update needed to systemd, as this Linux distro does not use systemctl'); + } } ########################################################### @@ -2323,7 +2635,7 @@ sub get_mysql_version { sub copy_httpd_conf { my ($instdir,$distro) = @_; my $configfile = 'httpd.conf'; - if ($distro =~ /^(?:centos|rhes|scientific|oracle)(\d+)$/) { + if ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) { if ($1 >= 7) { $configfile = 'apache2.4/httpd.conf'; } elsif ($1 > 5) { @@ -2370,7 +2682,7 @@ sub copy_mpm_conf { print_and_log("\n"); } else { my $logfail; - if ($distro =~ /^(?:centos|rhes|scientific|oracle)(\d+)$/) { + if ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) { if ($1 > 7) { $logfail = 1; } @@ -2414,11 +2726,13 @@ sub copy_apache2_debconf { $distname = $1; $version = $2; } - if (($distname eq 'ubuntu') && ($version > 12)) { + if ((($distname eq 'ubuntu') && ($version > 12)) || + (($distname eq 'debian') && ($version >= 10))) { $defaultconfig = "$apache2_sites_enabled_dir/000-default.conf"; } my ($skipconf,$skipsite,$skipstatus); - if (($distname eq 'ubuntu') && ($version > 12)) { + if ((($distname eq 'ubuntu') && ($version > 12)) || + (($distname eq 'debian') && ($version >= 10))) { my $apache2_conf_enabled_dir = '/etc/apache2/conf-enabled'; my $apache2_conf_available_dir = '/etc/apache2/conf-available'; my $defaultconf = $apache2_conf_enabled_dir.'/loncapa.conf'; @@ -2571,7 +2885,7 @@ sub copy_apache2_debconf { } } } - if ($distname eq 'ubuntu') { + if (($distname eq 'ubuntu') || ($distname eq 'debian')) { my $sitestatus = "$apache2_mods_available_dir/status.conf"; my $stdstatus = "$instdir/debian-ubuntu/status.conf"; if ((-e $sitestatus) && (-e $stdstatus)) {