--- doc/install/linux/install.pl 2024/06/13 01:21:59 1.89 +++ doc/install/linux/install.pl 2024/07/27 18:39:10 1.91 @@ -78,7 +78,7 @@ if (!open(LOG,">>loncapa_install.log")) &mt('Stopping execution.')."\n"; exit; } else { - print LOG '$Id: install.pl,v 1.89 2024/06/13 01:21:59 raeburn Exp $'."\n"; + print LOG '$Id: install.pl,v 1.91 2024/07/27 18:39:10 raeburn Exp $'."\n"; } # @@ -595,6 +595,9 @@ sub check_required { my ($sslhostsfilesref,$has_std,$has_int,$rewritenum,$nochgstd,$nochgint); ($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{'apachessl'},$sslhostsfilesref,$has_std,$has_int,$rewritenum, $nochgstd,$nochgint) = &chkapachessl($distro,$instdir,$hostname,$hostip); @@ -622,12 +625,20 @@ sub check_mysql_running { $process = 'mysqld'; $proc_owner = 'mysql'; } + if ($1 >= 16) { + $use_systemctl = 1; + } } elsif ($distro =~ /^debian(\w+)/) { - if ($1 >= 12) { + 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'; @@ -771,10 +782,10 @@ sub chkconfig { $daemon{'cups'} = 'cupsys'; } if ((($distro =~ /^ubuntu/) && ($version >= 18)) || - (($distro =~ /^debian/) && ($version >= 12))) { + (($distro =~ /^debian/) && ($version >= 10))) { $daemon{'ntp'} = 'chrony'; } - if (($distro =~ /^debian/) && ($version >= 12)) { + if (($distro =~ /^debian/) && ($version >= 11)) { $daemon{'mysql'} = 'mariadb'; } } elsif ($distro =~ /^fedora(\d+)/) { @@ -899,6 +910,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); @@ -1003,7 +1034,7 @@ sub chkapache { my $version = $2; my ($stdconf,$stdsite); if ((($distname eq 'ubuntu') && ($version > 12)) || - (($distname eq 'debian') && ($version >= 12))) { + (($distname eq 'debian') && ($version >= 10))) { $stdconf = "$instdir/debian-ubuntu/ubuntu14/loncapa_conf"; $stdsite = "$instdir/debian-ubuntu/ubuntu14/loncapa_sites"; } else { @@ -1015,7 +1046,7 @@ sub chkapache { } else { my ($configfile,$sitefile); if ((($distname eq 'ubuntu') && ($version > 12)) || - (($distname eq 'debian') && ($version >= 12))) { + (($distname eq 'debian') && ($version >= 10))) { $sitefile = '/etc/apache2/sites-available/loncapa.conf'; $configfile = '/etc/apache2/conf-available/loncapa.conf'; } else { @@ -1032,13 +1063,15 @@ sub chkapache { } } if ((!$fixapache) && ((($distname eq 'ubuntu') && ($version > 12)) || - (($distname eq 'debian') && ($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; } } @@ -1902,12 +1935,13 @@ 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 SSL 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('6.')." ".&mt('Configure systemd security settings for Apache web server.')." +".&mt('7.')." ".&mt('Configure SSL for Apache web server.')." +".&mt('8.')." ".&mt('Configure start-up of services.')." +".&mt('9.')." ".&mt('Check firewall settings.')." +".&mt('10.')." ".&mt('Stop services not used by LON-CAPA,')." ".&mt('i.e., services for a print server: [_1] daemon.',"'cups'")." -".&mt('10.')." ".&mt('Download LON-CAPA source code in readiness for installation.')." +".&mt('11.')." ".&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.')." @@ -1936,7 +1970,7 @@ my $instdir = `pwd`; chomp($instdir); my %callsub; -my @actions = ('wwwuser','pwauth','mysql','mysqlperms','apache', +my @actions = ('wwwuser','pwauth','mysql','mysqlperms','apache','systemd', 'apachessl','runlevels','firewall','stopsrvcs','download'); my %prompts = &texthash( wwwuser => "Create the 'www' user?", @@ -1944,7 +1978,8 @@ my %prompts = &texthash( mysql => 'Set-up the MySQL database?', mysqlperms => 'Set-up MySQL permissions?', apache => 'Configure Apache web server?', - apachessl => 'Configure SSL for Apache web server?', + systemd => 'Configure systemd security settings for Apache web server?', + apachessl => 'Configure SSL 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?', @@ -1986,6 +2021,7 @@ if (!$gotprereqs) { &mt('The following command can be used to install the package (and dependencies):')."\n\n". $updatecmd."\n\n"; if ($installnow eq '') { + print &mt('Stopping execution.')."\n"; exit; } else { print &mt('Run command? ~[Y/n~]'); @@ -2153,6 +2189,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{'apachessl'}) { my $targetdir = '/etc/httpd/conf.d'; if ($distro =~ /^(suse|sles)/) { @@ -2276,7 +2318,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) { @@ -2367,13 +2409,17 @@ if ($have_tarball && !$updateshown) { } $uses_sudo = 1; } elsif ($distro =~ /^debian(\d+)$/) { - if ($1 >= 12) { + 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"; @@ -2605,7 +2651,7 @@ sub kill_extra_services { if ($distro =~ /^(?:debian|ubuntu)(\d+)/) { my $version = $1; if ((($distro =~ /^ubuntu/) && ($version > 16)) || - (($distro =~ /^debian/) && ($version >= 12))) { + (($distro =~ /^debian/) && ($version >= 10))) { if (ref($uses_systemctl) eq 'HASH') { if ($uses_systemctl->{$service}) { if (`systemctl is-enabled $service`) { @@ -2681,7 +2727,7 @@ sub setup_mysql_permissions { $is_mariadb = 1; if ((($mysqlversion == 10) && ($mysqlminorversion >= 4)) || ($mysqlversion >= 11)) { $usescreate = 1; - } elsif (($mysqlversion == 10) && ($mysqlminorversion >= 2)) { + } elsif (($mysqlversion == 10) && ($mysqlminorversion >= 2)) { $usesauth = 1; } elsif (($mysqlversion == 5) && ($mysqlminorversion >= 5)) { $hasauthcol = 1; @@ -2818,6 +2864,116 @@ sub get_mysql_version { 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'); + } 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'); + } + } + } 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'); + } +} + ########################################################### ## ## RHEL/CentOS/Fedora/Scientific Linux @@ -3397,12 +3553,12 @@ sub copy_apache2_debconf { $version = $2; } if ((($distname eq 'ubuntu') && ($version > 12)) || - (($distname eq 'debian') && ($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)) || - (($distname eq 'debian') && ($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';