Annotation of doc/install/linux/install.pl, revision 1.45.2.20
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.20! raeburn 79: print LOG '$Id: install.pl,v 1.45.2.19 2024/06/30 20:10:29 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: ©_apache2_suseconf($instdir,$distro);
1.1 raeburn 1798: } elsif ($distro =~ /^(debian|ubuntu)/) {
1.28 raeburn 1799: ©_apache2_debconf($instdir,$distro);
1.1 raeburn 1800: } else {
1.14 raeburn 1801: ©_httpd_conf($instdir,$distro);
1.45.2.5 raeburn 1802: ©_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');
! 2530: } else {
! 2531: print_and_log('Could not open /etc/systemd/system/'.$service.'.d/override.conf for writing.');
! 2532: }
! 2533: } else {
! 2534: print_and_log('No change needed in /etc/systemd/system/'.$service.'.d/override.conf');
! 2535: }
! 2536: } else {
! 2537: print_and_log('Could not open /etc/systemd/system/'.$service.'.d/override.conf for reading.');
! 2538: }
! 2539: } else {
! 2540: if (open(my $fh,'>','/etc/systemd/system/'.$service.'.d/override.conf')) {
! 2541: print $fh '[Service]'."\n".'ProtectHome=no'."\n";
! 2542: close($fh);
! 2543: print_and_log('Created /etc/systemd/system/'.$service.'.d/override.conf');
! 2544: }
! 2545: }
! 2546: } else {
! 2547: print_and_log('No /etc/systemd/system/'.$service.'.d directory exists and creating one failed,');
! 2548: }
! 2549: } else {
! 2550: print_and_log('No update needed to systemd security settings for Apache web server.');
! 2551: }
! 2552: } else {
! 2553: print_and_log('No update needed to systemd, as this Linux distro does not use systemctl');
! 2554: }
! 2555: }
! 2556:
1.1 raeburn 2557: ###########################################################
2558: ##
2559: ## RHEL/CentOS/Fedora/Scientific Linux
2560: ## Copy LON-CAPA httpd.conf to /etc/httpd/conf
2561: ##
2562: ###########################################################
2563:
2564: sub copy_httpd_conf {
1.14 raeburn 2565: my ($instdir,$distro) = @_;
2566: my $configfile = 'httpd.conf';
1.45.2.18 raeburn 2567: if ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
1.29 raeburn 2568: if ($1 >= 7) {
2569: $configfile = 'apache2.4/httpd.conf';
2570: } elsif ($1 > 5) {
1.14 raeburn 2571: $configfile = 'new/httpd.conf';
2572: }
2573: } elsif ($distro =~ /^fedora(\d+)$/) {
1.29 raeburn 2574: if ($1 > 17) {
2575: $configfile = 'apache2.4/httpd.conf';
2576: } elsif ($1 > 10) {
1.14 raeburn 2577: $configfile = 'new/httpd.conf';
2578: }
2579: }
1.1 raeburn 2580: print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',"'httpd.conf'",
2581: "'/etc/httpd/conf/httpd.conf'")."\n");
2582: copy "/etc/httpd/conf/httpd.conf","/etc/httpd/conf/httpd.conf.original";
1.14 raeburn 2583: copy "$instdir/centos-rhes-fedora-sl/$configfile","/etc/httpd/conf/httpd.conf";
1.5 raeburn 2584: chmod(0444,"/etc/httpd/conf/httpd.conf");
1.1 raeburn 2585: print_and_log("\n");
2586: }
2587:
1.45.2.5 raeburn 2588: ###########################################################
2589: ##
2590: ## RHEL/CentOS/Fedora/Scientific Linux
2591: ## Copy LON-CAPA mpm.conf to /etc/httpd/conf.modules.d/00-mpm.conf
2592: ##
2593: ## The LON-CAPA mpm.conf enables the prefork MPM module in
2594: ## Apache. This is also the default for RHEL/CentOS/Oracle
2595: ## Linux 7 and earlier, and Fedora 26 and earlier. For more
2596: ## recent versions of those distros, the event MPM is enabled
2597: ## by default. After ©_mpm_conf() is run, the prefork MPM
2598: ## module will be enabled instead of the event MPM module.
2599: ##
2600: ###########################################################
2601:
2602: sub copy_mpm_conf {
2603: my ($instdir,$distro) = @_;
2604: my $mpmfile = 'mpm.conf';
2605: if ((-e "/etc/httpd/conf.modules.d/00-mpm.conf") &&
2606: (-e "$instdir/centos-rhes-fedora-sl/$mpmfile")) {
2607: print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',"'mpm.conf'",
2608: "'/etc/httpd/conf.modules.d/00-mpm.conf'")."\n");
2609: copy "$instdir/centos-rhes-fedora-sl/$mpmfile","/etc/httpd/conf.modules.d/00-mpm.conf";
2610: chmod(0644,"/etc/httpd/conf.modules.d/00-mpm.conf");
2611: print_and_log("\n");
2612: } else {
2613: my $logfail;
1.45.2.18 raeburn 2614: if ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
1.45.2.5 raeburn 2615: if ($1 > 7) {
2616: $logfail = 1;
2617: }
2618: } elsif ($distro =~ /^fedora(\d+)$/) {
2619: if ($1 > 26) {
2620: $logfail = 1;
2621: }
2622: }
2623: if ($logfail) {
2624: print_and_log(&mt('Warning: copying the LON-CAPA [_1] failed because [_2] and/or [_3] are missing.',
2625: $mpmfile,"'$instdir/centos-rhes-fedora-sl/$mpmfile'",
2626: "'/etc/httpd/conf.modules.d/00-mpm.conf'"));
2627: print_and_log("\n");
2628: }
2629: }
2630: }
2631:
1.1 raeburn 2632: #########################################################
2633: ##
1.17 raeburn 2634: ## Ubuntu/Debian -- copy our loncapa configuration file to
1.1 raeburn 2635: ## sites-available and set the symlink from sites-enabled.
2636: ##
2637: #########################################################
2638:
2639: sub copy_apache2_debconf {
1.28 raeburn 2640: my ($instdir,$distro) = @_;
1.6 raeburn 2641: my $apache2_mods_enabled_dir = '/etc/apache2/mods-enabled';
2642: my $apache2_mods_available_dir = '/etc/apache2/mods-available';
2643: foreach my $module ('headers.load','expires.load') {
2644: unless (-l "$apache2_mods_enabled_dir/$module") {
2645: symlink("$apache2_mods_available_dir/$module","$apache2_mods_enabled_dir/$module");
2646: print_and_log(&mt('Enabling "[_1]" Apache module.',$module)."\n");
2647: }
2648: }
1.28 raeburn 2649: my $apache2_sites_enabled_dir = '/etc/apache2/sites-enabled';
2650: my $apache2_sites_available_dir = '/etc/apache2/sites-available';
2651: my $defaultconfig = "$apache2_sites_enabled_dir/000-default";
1.45.2.10 raeburn 2652: my $defaultsite = "$apache2_sites_enabled_dir/loncapa.conf";
1.28 raeburn 2653: my ($distname,$version);
2654: if ($distro =~ /^(debian|ubuntu)(\d+)$/) {
2655: $distname = $1;
2656: $version = $2;
2657: }
1.45.2.19 raeburn 2658: if ((($distname eq 'ubuntu') && ($version > 12)) ||
2659: (($distname eq 'debian') && ($version >= 10))) {
1.28 raeburn 2660: $defaultconfig = "$apache2_sites_enabled_dir/000-default.conf";
2661: }
1.45.2.7 raeburn 2662: my ($skipconf,$skipsite,$skipstatus);
1.45.2.19 raeburn 2663: if ((($distname eq 'ubuntu') && ($version > 12)) ||
2664: (($distname eq 'debian') && ($version >= 10))) {
1.28 raeburn 2665: my $apache2_conf_enabled_dir = '/etc/apache2/conf-enabled';
2666: my $apache2_conf_available_dir = '/etc/apache2/conf-available';
1.33 raeburn 2667: my $defaultconf = $apache2_conf_enabled_dir.'/loncapa.conf';
1.45.2.7 raeburn 2668: if ((-e "$apache2_conf_available_dir/loncapa") && (-e "$instdir/debian-ubuntu/ubuntu14/loncapa_conf")) {
1.45.2.8 raeburn 2669: if (open(PIPE, "diff --brief $apache2_conf_available_dir/loncapa $instdir/debian-ubuntu/ubuntu14/loncapa_conf |")) {
1.45.2.7 raeburn 2670: my $diffres = <PIPE>;
2671: close(PIPE);
2672: chomp($diffres);
2673: if ($diffres) {
1.45.2.10 raeburn 2674: copy("$apache2_conf_available_dir/loncapa","$apache2_conf_available_dir/loncapa.conf.original");
2675: } else {
2676: copy("$apache2_conf_available_dir/loncapa","$apache2_conf_available_dir/loncapa.conf");
1.45.2.11 raeburn 2677: chdir($apache2_conf_enabled_dir);
2678: symlink('../conf-available/loncapa.conf','loncapa.conf');
2679: chdir($instdir);
1.45.2.7 raeburn 2680: }
2681: if (-l $defaultconf) {
2682: my $linkfname = readlink($defaultconf);
1.45.2.11 raeburn 2683: if ($linkfname ne '') {
2684: $linkfname = Cwd::abs_path(File::Spec->rel2abs($linkfname,$apache2_conf_enabled_dir));
2685: }
1.45.2.7 raeburn 2686: if ($linkfname eq "$apache2_conf_available_dir/loncapa") {
1.45.2.10 raeburn 2687: unlink($defaultconf);
2688: }
2689: }
2690: unlink("$apache2_conf_available_dir/loncapa");
2691: }
2692: }
2693: if ((-e "$apache2_conf_available_dir/loncapa.conf") && (-e "$instdir/debian-ubuntu/ubuntu14/loncapa_conf")) {
2694: if (open(PIPE, "diff --brief $apache2_conf_available_dir/loncapa.conf $instdir/debian-ubuntu/ubuntu14/loncapa_conf |")) {
2695: my $diffres = <PIPE>;
2696: close(PIPE);
2697: chomp($diffres);
2698: if ($diffres) {
2699: copy("$apache2_conf_available_dir/loncapa.conf","$apache2_conf_available_dir/loncapa.conf.original");
2700: }
2701: if (-l $defaultconf) {
2702: my $linkfname = readlink($defaultconf);
1.45.2.11 raeburn 2703: if ($linkfname ne '') {
2704: $linkfname = Cwd::abs_path(File::Spec->rel2abs($linkfname,$apache2_conf_enabled_dir));
2705: }
1.45.2.10 raeburn 2706: if ($linkfname eq "$apache2_conf_available_dir/loncapa.conf") {
1.45.2.7 raeburn 2707: unless ($diffres) {
2708: $skipconf = 1;
2709: }
2710: }
2711: }
2712: }
2713: }
2714: unless ($skipconf) {
2715: 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 2716: copy("$instdir/debian-ubuntu/ubuntu14/loncapa_conf","$apache2_conf_available_dir/loncapa.conf");
2717: chmod(0444,"$apache2_conf_available_dir/loncapa.conf");
1.45.2.7 raeburn 2718: if (-l $defaultconf) {
2719: unlink($defaultconf);
2720: }
1.45.2.11 raeburn 2721: chdir($apache2_conf_enabled_dir);
2722: symlink('../conf-available/loncapa.conf','loncapa.conf');
2723: chdir($instdir);
1.45.2.7 raeburn 2724: }
2725: my $stdsite = "$instdir/debian-ubuntu/ubuntu14/loncapa_site";
2726: if ((-e $stdsite) && (-e "$apache2_sites_available_dir/loncapa")) {
2727: if (open(PIPE, "diff --brief $stdsite $apache2_sites_available_dir/loncapa |")) {
2728: my $diffres = <PIPE>;
2729: close(PIPE);
2730: chomp($diffres);
2731: if ($diffres) {
1.45.2.10 raeburn 2732: copy("$apache2_sites_available_dir/loncapa","$apache2_sites_available_dir/loncapa.conf.original");
2733: } else {
2734: copy("$apache2_sites_available_dir/loncapa","$apache2_sites_available_dir/loncapa.conf");
1.45.2.7 raeburn 2735: }
2736: if (-l $defaultconfig) {
2737: my $linkfname = readlink($defaultconfig);
1.45.2.11 raeburn 2738: if ($linkfname ne '') {
2739: $linkfname = Cwd::abs_path(File::Spec->rel2abs($linkfname,$apache2_sites_enabled_dir));
2740: }
1.45.2.7 raeburn 2741: if ($linkfname eq "$apache2_sites_available_dir/loncapa") {
1.45.2.10 raeburn 2742: unlink($defaultconfig);
2743: }
2744: }
2745: unlink("$apache2_sites_available_dir/loncapa");
2746: }
2747: }
2748: if ((-e $stdsite) && (-e "$apache2_sites_available_dir/loncapa.conf")) {
2749: if (open(PIPE, "diff --brief $stdsite $apache2_sites_available_dir/loncapa.conf |")) {
2750: my $diffres = <PIPE>;
2751: close(PIPE);
2752: chomp($diffres);
2753: if ($diffres) {
2754: copy("$apache2_sites_available_dir/loncapa.conf","$apache2_sites_available_dir/loncapa.conf.original");
2755: }
2756: if (-l $defaultsite) {
2757: my $linkfname = readlink($defaultsite);
1.45.2.11 raeburn 2758: if ($linkfname ne '') {
2759: $linkfname = Cwd::abs_path(File::Spec->rel2abs($linkfname,$apache2_sites_enabled_dir));
2760: }
2761: if ($linkfname eq "$apache2_sites_available_dir/loncapa.conf") {
1.45.2.7 raeburn 2762: unless ($diffres) {
2763: $skipsite = 1;
2764: }
2765: }
2766: }
2767: }
2768: }
2769: unless ($skipsite) {
1.45.2.10 raeburn 2770: 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");
2771: copy("$instdir/debian-ubuntu/ubuntu14/loncapa_site","$apache2_sites_available_dir/loncapa.conf");
2772: chmod(0444,"$apache2_sites_available_dir/loncapa.conf");
1.45.2.11 raeburn 2773: chdir($apache2_sites_enabled_dir);
2774: symlink('../sites-available/loncapa.conf','loncapa.conf');
2775: chdir($instdir);
1.45.2.10 raeburn 2776: }
1.45.2.11 raeburn 2777: if (-l $defaultconfig) {
1.45.2.10 raeburn 2778: my $linkfname = readlink($defaultconfig);
1.45.2.11 raeburn 2779: if ($linkfname ne '') {
2780: $linkfname = Cwd::abs_path(File::Spec->rel2abs($linkfname,$apache2_sites_enabled_dir));
2781: }
2782: if ($linkfname eq "$apache2_sites_available_dir/000-default.conf") {
1.45.2.10 raeburn 2783: unlink($defaultconfig);
2784: }
1.45.2.7 raeburn 2785: }
2786: } else {
2787: if ((-e "$instdir/debian-ubuntu/loncapa") && (-e "$apache2_sites_available_dir/loncapa")) {
2788: if (open(PIPE, "diff --brief $instdir/debian-ubuntu/loncapa $apache2_sites_available_dir/loncapa |")) {
2789: my $diffres = <PIPE>;
2790: close(PIPE);
2791: chomp($diffres);
2792: if ($diffres) {
2793: copy("$apache2_sites_available_dir/loncapa","$apache2_sites_available_dir/loncapa.original");
2794: }
2795: if (-l $defaultconfig) {
2796: my $linkfname = readlink($defaultconfig);
2797: if ($linkfname eq "$apache2_sites_available_dir/loncapa") {
2798: unless ($diffres) {
2799: $skipsite = 1;
2800: }
2801: }
2802: }
2803: }
2804: }
2805: unless ($skipsite) {
2806: if (-l $defaultconfig) {
2807: unlink($defaultconfig);
2808: }
2809: 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");
2810: if (-e "$instdir/debian-ubuntu/loncapa") {
2811: copy("$instdir/debian-ubuntu/loncapa","$apache2_sites_available_dir/loncapa");
2812: chmod(0444,"$apache2_sites_available_dir/loncapa");
2813: symlink("$apache2_sites_available_dir/loncapa","$apache2_sites_enabled_dir/000-default");
2814: }
2815: }
2816: }
1.45.2.19 raeburn 2817: if (($distname eq 'ubuntu') || ($distname eq 'debian')) {
1.45.2.7 raeburn 2818: my $sitestatus = "$apache2_mods_available_dir/status.conf";
2819: my $stdstatus = "$instdir/debian-ubuntu/status.conf";
2820: if ((-e $sitestatus) && (-e $stdstatus)) {
2821: if (open(PIPE, "diff --brief $stdstatus $sitestatus |")) {
2822: my $diffres = <PIPE>;
2823: close(PIPE);
2824: chomp($diffres);
2825: if ($diffres) {
2826: copy("$apache2_mods_available_dir/status.conf","$apache2_mods_available_dir/status.conf.original");
2827: } else {
2828: $skipstatus = 1;
2829: }
2830: }
2831: }
2832: unless ($skipstatus) {
2833: if (-e $stdstatus) {
2834: print_and_log(&mt('Copying loncapa [_1] file to [_2],',"'status.conf'","'/etc/apache2/mods-available/status.conf'")."\n");
2835: copy($stdstatus,$sitestatus);
2836: chmod(0644,$sitestatus);
2837: }
2838: }
1.28 raeburn 2839: }
1.1 raeburn 2840: print_and_log("\n");
2841: }
2842:
2843: ###########################################################
2844: ##
2845: ## openSuSE/SLES Copy apache2 config files:
2846: ## default-server.conf, uid.conf, /etc/sysconfig/apache2
2847: ## and create symlink from /srv/www/conf to /etc/apache2
2848: ##
2849: ###########################################################
2850:
2851: sub copy_apache2_suseconf {
1.45.2.1 raeburn 2852: my ($instdir,$distro) = @_;
2853: my ($name,$version) = ($distro =~ /^(suse|sles)([\d\.]+)$/);
2854: my $conf_file = "$instdir/sles-suse/default-server.conf";
2855: if (($name eq 'sles') && ($version >= 12)) {
2856: $conf_file = "$instdir/sles-suse/apache2.4/default-server.conf";
2857: }
1.1 raeburn 2858: print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',
2859: "'default-server.conf'",
2860: "'/etc/apache2/default-server.conf'")."\n");
2861: if (!-e "/etc/apache2/default-server.conf.original") {
2862: copy "/etc/apache2/default-server.conf","/etc/apache2/default-server.conf.original";
2863: }
1.45.2.1 raeburn 2864: copy $conf_file,"/etc/apache2/default-server.conf";
1.5 raeburn 2865: chmod(0444,"/etc/apache2/default-server.conf");
1.1 raeburn 2866: # Make symlink for conf directory (included in loncapa_apache.conf)
2867: my $can_symlink = (eval { symlink('/etc/apache2','/srv/www/conf'); }, $@ eq '');
2868: if ($can_symlink) {
2869: &print_and_log(&mt('Symlink created for [_1] to [_2].',
2870: "'/srv/www/conf'","'/etc/apache2'")."\n");
2871: } else {
2872: &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");
2873: }
2874: ©_apache2_conf_files($instdir);
1.45.2.1 raeburn 2875: ©_sysconfig_apache2_file($instdir,$name,$version);
1.1 raeburn 2876: print_and_log("\n");
2877: }
2878:
2879: ###############################################
2880: ##
2881: ## Modify uid.conf
2882: ##
2883: ###############################################
2884: sub copy_apache2_conf_files {
2885: my ($instdir) = @_;
2886: print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',
2887: "'uid.conf'","'/etc/apache2/uid.conf'")."\n");
2888: if (!-e "/etc/apache2/uid.conf.original") {
2889: copy "/etc/apache2/uid.conf","/etc/apache2/uid.conf.original";
2890: }
1.9 raeburn 2891: copy "$instdir/sles-suse/uid.conf","/etc/apache2/uid.conf";
1.5 raeburn 2892: chmod(0444,"/etc/apache2/uid.conf");
1.1 raeburn 2893: }
2894:
2895: ###############################################
2896: ##
2897: ## Modify /etc/sysconfig/apache2
2898: ##
2899: ###############################################
2900: sub copy_sysconfig_apache2_file {
1.45.2.1 raeburn 2901: my ($instdir,$name,$version) = @_;
1.1 raeburn 2902: print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',"'sysconfig/apache2'","'/etc/sysconfig/apache2'")."\n");
2903: if (!-e "/etc/sysconfig/apache2.original") {
2904: copy "/etc/sysconfig/apache2","/etc/sysconfig/apache2.original";
2905: }
1.45.2.1 raeburn 2906: my $sysconf_file = "$instdir/sles-suse/sysconfig_apache2";
2907: if (($name eq 'sles') && ($version >= 12)) {
2908: $sysconf_file = "$instdir/sles-suse/apache2.4/sysconfig_apache2";
2909: }
2910: copy $sysconf_file,"/etc/sysconfig/apache2";
1.5 raeburn 2911: chmod(0444,"/etc/sysconfig/apache2");
1.1 raeburn 2912: }
2913:
2914: ###############################################
2915: ##
2916: ## Add/Modify /etc/insserv/overrides
2917: ##
2918: ###############################################
2919:
2920: sub update_SuSEfirewall2_setup {
2921: my ($instdir) = @_;
2922: print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',"'SuSEfirewall2_setup'","'/etc/insserv/overrides/SuSEfirewall2_setup'")."\n");
2923: if (!-e "/etc/insserv/overrides/SuSEfirewall2_setup") {
2924: if (!-d "/etc/insserv") {
2925: mkdir("/etc/insserv",0755);
2926: }
2927: if (!-d "/etc/insserv/overrides") {
2928: mkdir("/etc/insserv/overrides",0755);
2929: }
2930: } elsif (!-e "/etc/insserv/overrides/SuSEfirewall2_setup.original") {
2931: copy "/etc/insserv/overrides/SuSEfirewall2_setup","/etc/insserv/overrides/SuSEfirewall2_setup.original"
2932: }
1.9 raeburn 2933: copy "$instdir/sles-suse/SuSEfirewall2_setup","/etc/insserv/overrides/SuSEfirewall2_setup";
1.5 raeburn 2934: chmod(0444,"/etc/insserv/overrides/SuSEfirewall2_setup");
2935: }
2936:
2937: sub get_iptables_rules {
2938: my ($distro,$instdir,$apachefw) = @_;
2939: my (@fwchains,@ports);
2940: if (&firewall_is_active()) {
2941: my $iptables = &get_pathto_iptables();
2942: if ($iptables ne '') {
2943: @fwchains = &get_fw_chains($iptables,$distro);
2944: }
2945: }
2946: if (ref($apachefw) eq 'HASH') {
2947: foreach my $service ('http','https') {
2948: unless ($apachefw->{$service}) {
2949: push (@ports,$service);
2950: }
2951: }
2952: } else {
2953: @ports = ('http','https');
2954: }
2955: if (@ports == 0) {
2956: return;
2957: }
2958: my $ask_to_enable;
2959: if (-e "/etc/iptables.loncapa.rules") {
1.9 raeburn 2960: if (open(PIPE, "diff --brief $instdir/debian-ubuntu/iptables.loncapa.rules /etc/iptables.loncapa.rules |")) {
1.5 raeburn 2961: my $diffres = <PIPE>;
2962: close(PIPE);
2963: chomp($diffres);
2964: if ($diffres) {
2965: print &mt('Warning: [_1] exists but differs from LON-CAPA supplied file.','/etc/iptables.loncapa.rules')."\n";
2966: }
2967: } else {
2968: print &mt('Error: unable to open [_1] to compare contents with LON-CAPA supplied file.','/etc/iptables.loncapa.rules')."\n";
2969: }
2970: } else {
1.9 raeburn 2971: if (-e "$instdir/debian-ubuntu/iptables.loncapa.rules") {
2972: copy "$instdir/debian-ubuntu/iptables.loncapa.rules","/etc/iptables.loncapa.rules";
1.5 raeburn 2973: chmod(0600,"/etc/iptables.loncapa.rules");
2974: }
2975: }
2976: if (-e "/etc/iptables.loncapa.rules") {
2977: if (-e "/etc/network/if-pre-up.d/iptables") {
1.9 raeburn 2978: if (open(PIPE, "diff --brief $instdir/debian-ubuntu/iptables /etc/network/if-pre-up/iptables |")) {
1.5 raeburn 2979: my $diffres = <PIPE>;
2980: close(PIPE);
2981: chomp($diffres);
2982: if ($diffres) {
2983: print &mt('Warning: [_1] exists but differs from LON-CAPA supplied file.','/etc/network/if-pre-up.d/iptables')."\n";
2984: }
2985: } else {
2986: print &mt('Error: unable to open [_1] to compare contents with LON-CAPA supplied file.','/etc/network/if-pre-up.d/iptables')."\n";
2987: }
2988: } else {
1.9 raeburn 2989: copy "$instdir/debian-ubuntu/iptables","/etc/network/if-pre-up.d/iptables";
1.5 raeburn 2990: chmod(0755,"/etc/network/if-pre-up.d/iptables");
2991: 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'));
2992: $ask_to_enable = 1;
2993: }
2994: }
2995: return $ask_to_enable;
1.1 raeburn 2996: }
2997:
2998: sub download_loncapa {
2999: my ($instdir,$lctarball) = @_;
3000: my ($have_tarball,$updateshown);
3001: if (! -e "$instdir/$lctarball") {
3002: print_and_log(&mt('Retrieving LON-CAPA source files from: [_1]',
3003: 'http://install.loncapa.org')."\n");
3004: system("wget http://install.loncapa.org/versions/$lctarball ".
3005: "2>/dev/null 1>/dev/null");
3006: if (! -e "./$lctarball") {
3007: print &mt('Unable to retrieve LON-CAPA source files from: [_1].',
3008: "http://install.loncapa.org/versions/$lctarball")."\n";
3009: } else {
3010: $have_tarball = 1;
3011: }
3012: print_and_log("\n");
3013: } else {
3014: $have_tarball = 1;
3015: print_and_log("
3016: ------------------------------------------------------------------------
3017:
1.45.2.16 raeburn 3018: ".&mt('You seem to have a version of [_1] in [_2]',$lctarball,$instdir)."\n".
1.1 raeburn 3019: &mt('This copy will be used and a new version will NOT be downloaded.')."\n".
3020: &mt('If you wish, you may download a new version by executing:')."
3021:
1.45.2.16 raeburn 3022: wget http://install.loncapa.org/versions/$lctarball
1.1 raeburn 3023:
3024: ------------------------------------------------------------------------
3025: ");
3026: }
3027:
3028: ##
1.45.2.16 raeburn 3029: ## untar loncapa-X.Y.Z.tar.gz
1.1 raeburn 3030: ##
3031: if ($have_tarball) {
1.45.2.16 raeburn 3032: my $homedir = '/root';
3033: my ($targetdir,$chdircmd,$updatecmd);
3034: if (($distro =~ /^ubuntu/) && ($instdir ne $homedir)) {
3035: ($homedir) = ($instdir =~ m{^(.*)/[^/]+$});
3036: $updatecmd = 'sudo ./UPDATE';
3037: } else {
3038: $updatecmd = './UPDATE';
3039: }
1.1 raeburn 3040: print_and_log(&mt('Extracting LON-CAPA source files')."\n");
1.45.2.16 raeburn 3041: if (-e $homedir) {
3042: writelog(`tar zxf $instdir/$lctarball --directory $homedir`);
3043: $targetdir = $homedir;
3044: } else {
3045: writelog(`tar zxf $instdir/$lctarball`);
3046: $targetdir = $instdir;
3047: }
3048: if ($lctarball =~ /^loncapa\-(\d+\.\d+\.\d+(?:|[^.]+))\.tar\.gz$/) {
3049: $chdircmd = "cd $targetdir/loncapa-".$1;
3050: } else {
3051: $chdircmd = "cd $targetdir/loncapa-X.Y.Z (X.Y.Z should correspond to a version number like '2.11.3')";
3052: }
1.1 raeburn 3053: print_and_log("\n");
3054: print &mt('LON-CAPA source files extracted.')."\n".
1.45.2.16 raeburn 3055: &mt('It remains for you to execute the following commands:').
3056: "\n$chdircmd\n$updatecmd\n".
3057: &mt('If you have any trouble, please see [_1] and [_2]',
3058: 'http://install.loncapa.org/','http://help.loncapa.org/')."\n";
1.1 raeburn 3059: $updateshown = 1;
3060: }
3061: return ($have_tarball,$updateshown);
3062: }
3063:
3064: close LOG;
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>