--- doc/install/linux/install.pl 2016/08/09 15:20:45 1.37 +++ doc/install/linux/install.pl 2018/07/11 01:58:41 1.46 @@ -26,7 +26,11 @@ use strict; use File::Copy; use Term::ReadKey; +use Sys::Hostname::FQDN(); use DBI; +use Cwd(); +use File::Basename(); +use lib File::Basename::dirname(Cwd::abs_path($0)); use LCLocalization::localize; # ========================================================= The language handle @@ -72,7 +76,7 @@ if (!open(LOG,">>loncapa_install.log")) &mt('Stopping execution.')."\n"; exit; } else { - print LOG '$Id: install.pl,v 1.37 2016/08/09 15:20:45 raeburn Exp $'."\n"; + print LOG '$Id: install.pl,v 1.46 2018/07/11 01:58:41 raeburn Exp $'."\n"; } # @@ -277,6 +281,26 @@ sub get_distro { return ($distro,$packagecmd,$updatecmd,$installnow); } +sub get_hostname { + my $hostname; + print &mt('Enter the hostname of this server, e.g., loncapa.somewhere.edu'."\n"); + my $choice = ; + chomp($choice); + $choice =~ s/(^\s+|\s+$)//g; + if ($choice eq '') { + print &mt("Hostname you entered was either blank or contanied only white space.\n"); + } elsif ($choice =~ /^[\w\.\-]+$/) { + $hostname = $choice; + } else { + print &mt("Hostname you entered was invalid -- a hostname may only contain letters, numbers, - and .\n"); + } + while ($hostname eq '') { + $hostname = &get_hostname(); + } + print "\n"; + return $hostname; +} + sub check_prerequisites { my ($packagecmd,$distro) = @_; my $gotprereqs; @@ -386,7 +410,8 @@ sub check_required { return ($distro,$gotprereqs,$localecmd); } my ($mysqlon,$mysqlsetup,$mysqlrestart,$dbh,$has_pass,$has_lcdb,%recommended, - $downloadstatus,$filetouse,$production,$testing,$apachefw,$tostop,$uses_systemctl); + $downloadstatus,$filetouse,$production,$testing,$apachefw,$tostop, + $uses_systemctl,$hostname); my $wwwuid = &uid_of_www(); my $wwwgid = getgrnam('www'); if (($wwwuid eq '') || ($wwwgid eq '')) { @@ -395,6 +420,16 @@ sub check_required { unless( -e "/usr/local/sbin/pwauth") { $recommended{'pwauth'} = 1; } + my $hostname = Sys::Hostname::FQDN::fqdn(); + if ($hostname eq '') { + $hostname =&get_hostname(); + } else { + print &mt("Hostname detected: $hostname. Is that correct? ~[Y/n~]"); + if (!&get_user_selection(1)) { + $hostname =&get_hostname(); + } + } + print_and_log(&mt('Hostname is [_1]',$hostname)."\n"); $mysqlon = &check_mysql_running($distro); if ($mysqlon) { my $mysql_has_wwwuser = &check_mysql_wwwuser(); @@ -426,12 +461,13 @@ sub check_required { ($recommended{'firewall'},$apachefw) = &chkfirewall($distro); ($recommended{'runlevels'},$tostop,$uses_systemctl) = &chkconfig($distro,$instdir); $recommended{'apache'} = &chkapache($distro,$instdir); + $recommended{'apachessl'} = &chkapachessl($distro,$instdir,$hostname); $recommended{'stopsrvcs'} = &chksrvcs($distro,$tostop); ($recommended{'download'},$downloadstatus,$filetouse,$production,$testing) = &need_download(); return ($distro,$gotprereqs,$localecmd,$packagecmd,$updatecmd,$installnow, $mysqlrestart,\%recommended,$dbh,$has_pass,$has_lcdb,$downloadstatus, - $filetouse,$production,$testing,$apachefw,$uses_systemctl); + $filetouse,$production,$testing,$apachefw,$uses_systemctl,$hostname); } sub check_mysql_running { @@ -454,7 +490,7 @@ sub check_mysql_running { $proc_owner = 'mysql'; $use_systemctl = 1; } - if ($1 >= 22) { + if ($1 >= 19) { $mysqldaemon ='mariadb'; } } elsif ($distro =~ /^(?:centos|rhes|scientific)(\d+)/) { @@ -467,6 +503,8 @@ sub check_mysql_running { } elsif ($distro =~ /^sles(\d+)/) { if ($1 >= 12) { $use_systemctl = 1; + $proc_owner = 'mysql'; + $process = 'mysqld'; } } elsif ($distro =~ /^suse(\d+)/) { if ($1 >= 13) { @@ -559,7 +597,15 @@ sub chkconfig { my $version = $1; @runlevels = qw/2 3 4 5/; @norunlevels = qw/0 1 6/; - $checker_bin = '/usr/sbin/sysv-rc-conf'; + if (($distro =~ /^ubuntu/) && ($version <= 16)) { + $checker_bin = '/usr/sbin/sysv-rc-conf'; + } else { + $uses_systemctl{'ntp'} = 1; + $uses_systemctl{'mysql'} = 1; + $uses_systemctl{'apache'} = 1; + $uses_systemctl{'memcached'} = 1; + $uses_systemctl{'cups'} = 1; + } $daemon{'mysql'} = 'mysql'; $daemon{'apache'} = 'apache2'; $daemon{'ntp'} = 'ntp'; @@ -577,7 +623,7 @@ sub chkconfig { $uses_systemctl{'memcached'} = 1; $uses_systemctl{'cups'} = 1; } - if ($version >= 22) { + if ($version >= 19) { $daemon{'mysql'} = 'mariadb'; } } elsif ($distro =~ /^(?:centos|rhes|scientific)(\d+)/) { @@ -836,6 +882,44 @@ sub chkapache { return $fixapache; } +sub chkapachessl { + my ($distro,$instdir,$hostname) = @_; + my $fixapachessl = 1; + my $stdconf = "$instdir/loncapassl.conf"; + if (!-e $stdconf) { + $fixapachessl = 0; + print &mt('Warning: No LON-CAPA SSL Apache configuration file found for installation check.')."\n"; + } else { + my $sslfile; + if ($distro =~ /^(debian|ubuntu)(\d+)$/) { + $sslfile = '/etc/apache2/sites-available/loncapassl.conf'; + } elsif ($distro =~ /(suse|sles)/) { + $sslfile = '/etc/apache2/vhosts.d/loncapassl.conf'; + } else { + $sslfile = '/etc/httpd/conf.d/loncapassl.conf'; + } + if ((-e $sslfile) && (-e $stdconf)) { + if (open(PIPE, "diff -y -bi --suppress-common-lines $stdconf $sslfile |")) { + my $diffres = ; + close(PIPE); + chomp($diffres); + if ($diffres =~ /^\QServerName internal-{[[[[Hostname]]]]}\E\s+\|\s+\QServerName internal-\E$hostname$/) { + $fixapachessl = 0; + } + } + } + unless ($fixapachessl) { + if ($distro =~ /^(debian|ubuntu)(\d+)$/) { + unless ((-l '/etc/apache2/sites-enabled/loncapassl.conf') && + (readlink('/etc/apache2/sites-enabled/loncapassl.conf') eq '/etc/apache2/sites-available/loncapassl.conf')) { + print_and_log(&mt("Warning, use: 'sudo a2ensite loncapassl.conf' to activate LON-CAPA SSL Apache config\n")); + } + } + } + } + return $fixapachessl; +} + sub chksrvcs { my ($distro,$tostop) = @_; my %stopsrvcs; @@ -1227,11 +1311,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 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('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.')." @@ -1261,25 +1346,26 @@ chomp($instdir); my %callsub; my @actions = ('wwwuser','pwauth','mysql','mysqlperms','apache', - 'runlevels','firewall','stopsrvcs','download'); + 'apachessl','runlevels','firewall','stopsrvcs','download'); my %prompts = &texthash( wwwuser => "Create the 'www' user?", pwauth => 'Install the package LON-CAPA uses to authenticate users?', mysql => 'Set-up the MySQL database?', mysqlperms => 'Set-up MySQL permissions?', apache => 'Configure 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?', download => 'Download LON-CAPA source code in readiness for installation?', ); -print "\n".&mt('Checking system status ...')."\n"; +print "\n".&mt('Checking system status ...')."\n\n"; my $dsn = "DBI:mysql:database=mysql"; my ($distro,$gotprereqs,$localecmd,$packagecmd,$updatecmd,$installnow,$mysqlrestart, $recommended,$dbh,$has_pass,$has_lcdb,$downloadstatus,$filetouse,$production, - $testing,$apachefw,$uses_systemctl) = &check_required($instdir,$dsn); + $testing,$apachefw,$uses_systemctl,$hostname) = &check_required($instdir,$dsn); if ($distro eq '') { print "\n".&mt('Linux distribution could not be verified as a supported distribution.')."\n". &mt('The following are supported: [_1].', @@ -1307,7 +1393,6 @@ 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~]'); @@ -1447,16 +1532,36 @@ if ($dbh) { if ($callsub{'apache'}) { if ($distro =~ /^(suse|sles)/) { - ©_apache2_suseconf($instdir); + ©_apache2_suseconf($instdir,$hostname); } elsif ($distro =~ /^(debian|ubuntu)/) { - ©_apache2_debconf($instdir,$distro); + ©_apache2_debconf($instdir,$distro,$hostname); } else { - ©_httpd_conf($instdir,$distro); + ©_httpd_conf($instdir,$distro,$hostname); } } else { print_and_log(&mt('Skipping configuration of Apache web server.')."\n"); } +if ($callsub{'apachessl'}) { + if ($distro =~ /^(suse|sles)/) { + ©_apache_sslconf_file($instdir,'/etc/apache2/vhosts.d',$hostname); + } elsif ($distro =~ /^(debian|ubuntu)/) { + my $apache2_sites_available_dir = '/etc/apache2/sites-available'; + if (©_apache_sslconf_file($instdir,$apache2_sites_available_dir,$hostname)) { + my $apache2_sites_enabled_dir = '/etc/apache2/sites-enabled'; + my $made_symlink = eval { symlink("$apache2_sites_available_dir/loncapassl.conf","$apache2_sites_enabled_dir/loncapassl.conf"); 1 }; + if ($made_symlink) { + print_and_log(&mt('Enabling "[_1]" Apache SSL configuration.','loncapassl.conf')."\n"); + } + } + } else { + ©_apache_sslconf_file($instdir,'/etc/httpd/conf.d',$hostname); + } + print_and_log("\n"); +} else { + print_and_log(&mt('Skipping configuration of SSL for Apache web server.')."\n"); +} + if ($callsub{'runlevels'}) { my $count = 0; if (ref($recommended) eq 'HASH') { @@ -1517,7 +1622,7 @@ if ($callsub{'firewall'}) { } if ($callsub{'stopsrvcs'}) { - &kill_extra_services($distro,$recommended->{'stopsrvcs'}); + &kill_extra_services($distro,$recommended->{'stopsrvcs'},$uses_systemctl); } else { &print_and_log(&mt('Skipping stopping unnecessary service ([_1] daemons).',"'cups','memcached'")."\n"); } @@ -1704,7 +1809,7 @@ END } sub kill_extra_services { - my ($distro,$stopsrvcs) = @_; + my ($distro,$stopsrvcs,$uses_systemctl) = @_; if (ref($stopsrvcs) eq 'HASH') { my @stopping = sort(keys(%{$stopsrvcs})); if (@stopping) { @@ -1735,8 +1840,19 @@ sub kill_extra_services { } } &print_and_log(&mt('Removing [_1] from startup.',$service)."\n"); - if ($distro =~ /^(debian|ubuntu)/) { - &print_and_log(`update-rc.d -f $daemon remove`); + if ($distro =~ /^(?:debian|ubuntu)(\d+)/) { + my $version = $1; + if (($distro =~ /^ubuntu/) && ($version > 16)) { + if (ref($uses_systemctl) eq 'HASH') { + if ($uses_systemctl->{$service}) { + if (`systemctl is-enabled $service`) { + &print_and_log(`systemctl disable $service`); + } + } + } + } else { + &print_and_log(`update-rc.d -f $daemon remove`); + } } else { if (ref($uses_systemctl) eq 'HASH') { if ($uses_systemctl->{$service}) { @@ -1786,14 +1902,28 @@ CREATE TABLE IF NOT EXISTS metadata (tit sub setup_mysql_permissions { my ($dbh,$has_pass,@mysql_lc_commands) = @_; - my ($mysqlversion,$mysqlsubver) = &get_mysql_version(); - my ($usesauth,@mysql_commands); - if (($mysqlversion > 5.7) || (($mysqlversion == 5.7) && ($mysqlsubver > 5))) { - @mysql_commands = ("INSERT user (Host, User, ssl_cipher, x509_issuer, x509_subject) VALUES('localhost','www','','','')", - "ALTER USER 'www'\@'localhost' IDENTIFIED BY 'localhostkey'"); - $usesauth = 1; + my ($mysqlversion,$mysqlsubver,$mysqlname) = &get_mysql_version(); + my ($usesauth,$hasauthcol,@mysql_commands); + if ($mysqlname =~ /^MariaDB/i) { + if ($mysqlversion >= 10.2) { + $usesauth = 1; + } elsif ($mysqlversion >= 5.5) { + $hasauthcol = 1; + } + } else { + if (($mysqlversion > 5.7) || (($mysqlversion == 5.7) && ($mysqlsubver > 5))) { + $usesauth = 1; + } elsif (($mysqlversion >= 5.6) || (($mysqlversion == 5.5) && ($mysqlsubver >= 7))) { + $hasauthcol = 1; + } + } + if ($usesauth) { + @mysql_commands = ("INSERT user (Host, User, ssl_cipher, x509_issuer, x509_subject, authentication_string) VALUES('localhost','www','','','','')", + "ALTER USER 'www'\@'localhost' IDENTIFIED WITH mysql_native_password BY 'localhostkey'"); + } elsif ($hasauthcol) { + @mysql_commands = ("INSERT user (Host, User, Password, ssl_cipher, x509_issuer, x509_subject, authentication_string) VALUES('localhost','www',password('localhostkey'),'','','','');"); } else { - @mysql_commands = ("INSERT user (Host, User, Password) VALUES('localhost','www',password('localhostkey'));"); + @mysql_commands = ("INSERT user (Host, User, Password, ssl_cipher, x509_issuer, x509_subject) VALUES('localhost','www',password('localhostkey'),'','','');"); } if ($mysqlversion < 4) { push (@mysql_commands," @@ -1844,7 +1974,7 @@ INSERT db (Host,Db,User,Select_priv,Inse } } if ($got_passwd) { - my (@newpass_cmds) = &new_mysql_rootpasswd($newmysqlpass); + my (@newpass_cmds) = &new_mysql_rootpasswd($newmysqlpass,$usesauth); push(@mysql_commands,@newpass_cmds); } else { print_and_log(&mt('Failed to get MySQL root password from user input.')."\n"); @@ -1853,7 +1983,6 @@ INSERT db (Host,Db,User,Select_priv,Inse if (@mysql_commands) { foreach my $cmd (@mysql_commands) { $dbh->do($cmd) || print $dbh->errstr."\n"; - } } if (@mysql_lc_commands) { @@ -1877,7 +2006,7 @@ INSERT db (Host,Db,User,Select_priv,Inse sub new_mysql_rootpasswd { my ($currmysqlpass,$usesauth) = @_; if ($usesauth) { - return ("ALTER USER 'root'\@'localhost' IDENTIFIED BY '$currmysqlpass'", + return ("ALTER USER 'root'\@'localhost' IDENTIFIED WITH mysql_native_password BY '$currmysqlpass'", "FLUSH PRIVILEGES;"); } else { return ("SET PASSWORD FOR 'root'\@'localhost'=PASSWORD('$currmysqlpass')", @@ -1886,17 +2015,17 @@ sub new_mysql_rootpasswd { } sub get_mysql_version { - my ($version,$subversion); + my ($version,$subversion,$name); if (open(PIPE," mysql -V |")) { my $info = ; chomp($info); close(PIPE); - ($version,$subversion) = ($info =~ /(\d+\.\d+)\.(\d+)[\-\w]*,/); + ($version,$subversion,$name) = ($info =~ /(\d+\.\d+)\.(\d+)\-?(\w*),/); } else { print &mt('Could not determine which version of MySQL is installed.'). "\n"; } - return ($version,$subversion); + return ($version,$subversion,$name); } ########################################################### @@ -1907,7 +2036,7 @@ sub get_mysql_version { ########################################################### sub copy_httpd_conf { - my ($instdir,$distro) = @_; + my ($instdir,$distro,$hostname) = @_; my $configfile = 'httpd.conf'; if ($distro =~ /^(?:centos|rhes|scientific)(\d+)$/) { if ($1 >= 7) { @@ -1930,6 +2059,47 @@ sub copy_httpd_conf { print_and_log("\n"); } +############################################### +## +## Copy/Modify loncapassl.conf +## +############################################### + +sub copy_apache_sslconf_file { + my ($instdir,$targetdir,$hostname) = @_; + my ($success,$error); + if (-e "$instdir/loncapassl.conf") { + if (open(my $fh,'<',"$instdir/loncapassl.conf")) { + if (open(my $out,'>',"$targetdir/loncapassl.conf")) { + while (<$fh>) { + if (/^\QServerName internal-\E/) { + chomp(); + s/^(\QServerName internal-\E)(.*)$/$1$hostname\n/; + } + print $out $_; + } + $success = 1; + } else { + $error = "Could not write to $targetdir/loncapassl.conf"; + } + } else { + $error = "Could not read from $instdir/loncapassl.conf"; + } + } else { + $error = "File to copy from: $instdir/loncapassl.conf does not exist"; + } + if ($success) { + print_and_log(&mt('Successfully copied [_1] to [_2].',"'loncapassl.conf'","'$targetdir/loncapassl.conf'")."\n"); + chmod(0444,"$targetdir/loncapassl.conf"); + } else { + print_and_log(&mt('Failed to copy [_1] to [_2].',"'loncapassl.conf'","'$targetdir/loncapassl.conf'")."\n"); + if ($error) { + print_and_log("$error\n"); + } + } + return $success; +} + ######################################################### ## ## Ubuntu/Debian -- copy our loncapa configuration file to @@ -1938,7 +2108,7 @@ sub copy_httpd_conf { ######################################################### sub copy_apache2_debconf { - my ($instdir,$distro) = @_; + my ($instdir,$distro,$hostname) = @_; my $apache2_mods_enabled_dir = '/etc/apache2/mods-enabled'; my $apache2_mods_available_dir = '/etc/apache2/mods-available'; foreach my $module ('headers.load','expires.load') { @@ -2000,7 +2170,7 @@ sub copy_apache2_debconf { ########################################################### sub copy_apache2_suseconf { - my ($instdir) = @_; + my ($instdir,$hostname) = @_; print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].', "'default-server.conf'", "'/etc/apache2/default-server.conf'")."\n");