1: #!/usr/bin/perl
2: #
3: # The LearningOnline Network with CAPA
4: # Checks status of RPM packages on system.
5: #
6: # $Id: CHECKRPMS,v 1.17 2017/04/09 14:54:02 raeburn Exp $
7: #
8: # Copyright Michigan State University Board of Trustees
9: #
10: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
11: #
12: # LON-CAPA is free software; you can redistribute it and/or modify
13: # it under the terms of the GNU General Public License as published by
14: # the Free Software Foundation; either version 2 of the License, or
15: # (at your option) any later version.
16: #
17: # LON-CAPA is distributed in the hope that it will be useful,
18: # but WITHOUT ANY WARRANTY; without even the implied warranty of
19: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20: # GNU General Public License for more details.
21: #
22: # You should have received a copy of the GNU General Public License
23: # along with LON-CAPA; if not, write to the Free Software
24: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25: #
26: # /home/httpd/html/adm/gpl.txt
27: #
28: # http://www.lon-capa.org/
29: #
30:
31: =pod
32:
33: =head1 NAME
34:
35: B<CHECKRPMS> - automated status report about RPMs (RHEL/Fedora/CentOS/SuSE)
36: or debs (Debian/Ubuntu) on a system.
37:
38: =head1 DESCRIPTION
39:
40: This file automates the process of checking for available updates
41: to LON-CAPA systems. distprobe is used to determine the Linux distribution.
42:
43: The utility which is used to complete the check depends on the distro:
44:
45: fedora, rhel >= 5, centos, scientific - yum
46: fedora >= 22 - dnf
47: suse 9.X and sles9 - you
48: suse 10.2,10.3,11.1,11.2,11.3,11.4,sles11 - zypper
49: sles10,suse10.1 - rug
50: rhel 4 - up2date
51: debian, ubuntu - apt-get
52: others - check-rpms
53:
54: Created by amalgamating previous distribution-specific CHECKRPMS.dist files (where dist was one of: fedora, rhel, suse, sles10, default).
55:
56: Must be run as root or www.
57:
58: =cut
59:
60: use strict;
61: use lib '/home/httpd/lib/perl/';
62: use LONCAPA::Configuration;
63: use Apache::loncommon();
64:
65: my $tmpfile = '/tmp/CHECKRPMS.'.$$;
66: my $perlvar= LONCAPA::Configuration::read_conf('loncapa.conf');
67: my $docroot = $perlvar->{'lonDocRoot'};
68:
69: # Determine who we email
70: my $defdom = $perlvar->{'lonDefDomain'};
71: my $origmail = $perlvar->{'lonAdmEMail'};
72: my $emailto = &Apache::loncommon::build_recipient_list(undef,
73: 'packagesmail',$defdom,$origmail);
74: my $subj = $perlvar->{'lonHostID'};
75:
76: # Get Linux distro
77: open(PIPE, "$perlvar->{'lonDaemons'}/distprobe |");
78: my $distro = <PIPE>;
79: close(PIPE);
80:
81: undef($perlvar);
82:
83: my $hostname = `hostname`;
84: chomp($hostname);
85: open(TMPFILE,">$tmpfile");
86: print TMPFILE localtime(time).' '.$hostname."\n";
87: close(TMPFILE);
88:
89: if ($docroot ne '') {
90: if (-e "$docroot/lon-status/checkrpms.txt") {
91: unlink("$docroot/lon-status/checkrpms.txt");
92: }
93: }
94:
95: my ($cmd,$send,$addsubj);
96: if ($distro =~ /^fedora(\d+)$/) {
97: my $version =$1;
98: if ($version > 21) {
99: $cmd = 'dnf update';
100: &prepare_msg($tmpfile,$cmd);
101: ($send,$addsubj) = &check_with_dnf($tmpfile);
102: } else {
103: $cmd = 'yum update';
104: &prepare_msg($tmpfile,$cmd);
105: ($send,$addsubj) = &check_with_yum($tmpfile);
106: }
107: } elsif ($distro =~ /^(suse|sles)9\.?\d?$/) {
108: $cmd = 'you';
109: &prepare_msg($tmpfile,$cmd);
110: ($send,$addsubj) = &check_with_you($tmpfile);
111: } elsif ($distro =~ /^suse(\d{2,})\.(\d+)$/) {
112: my $version =$1;
113: my $subversion = $2;
114: if (($version > 10) || (($version == 10) && ($subversion > 1))) {
115: $cmd = 'zypper up';
116: &prepare_msg($tmpfile,$cmd);
117: ($send,$addsubj) = &check_with_zypper($tmpfile);
118: } else {
119: $cmd = 'rug up';
120: &prepare_msg($tmpfile,$cmd);
121: ($send,$addsubj) = &check_with_rug($tmpfile);
122: }
123: } elsif ($distro =~ /^sles10$/) {
124: $cmd = 'rug up';
125: &prepare_msg($tmpfile,$cmd);
126: ($send,$addsubj) = &check_with_rug($tmpfile);
127: } elsif ($distro =~ /^sles(\d+)$/) {
128: $cmd = 'zypper up';
129: &prepare_msg($tmpfile,$cmd);
130: ($send,$addsubj) = &check_with_zypper($tmpfile);
131: } elsif ($distro =~ /^rhes(\d+)$/) {
132: my $version = $1;
133: if ($version == 4) {
134: $cmd ='up2date -u --nox';
135: &prepare_msg($tmpfile,$cmd);
136: ($send,$addsubj) = &check_with_up2date($tmpfile);
137: } elsif ($version > 4) {
138: $cmd = 'yum update';
139: &prepare_msg($tmpfile,$cmd);
140: ($send,$addsubj) = &check_with_yum($tmpfile);
141: }
142: } elsif ($distro =~ /^centos\d+$/) {
143: $cmd = 'yum update';
144: &prepare_msg($tmpfile,$cmd);
145: ($send,$addsubj) = &check_with_yum($tmpfile);
146: } elsif ($distro =~ /^scientific\d+$/) {
147: $cmd = 'yum update';
148: &prepare_msg($tmpfile,$cmd);
149: ($send,$addsubj) = &check_with_yum($tmpfile);
150: } elsif ($distro =~ /^(debian|ubuntu)\d+/) {
151: $cmd = 'apt-get upgrade';
152: &prepare_msg($tmpfile,$cmd);
153: ($send,$addsubj) = &check_with_apt($tmpfile);
154: } else {
155: $cmd = '/usr/local/bin/check-rpms --update';
156: ($send,$addsubj) = &check_with_checkrpms($tmpfile);
157: }
158: if ($send) {
159: $subj .= $addsubj;
160: if ($docroot ne '') {
161: system("cat $tmpfile > $docroot/lon-status/checkrpms.txt");
162: if ($< == 0) {
163: system("chown www:www $docroot/lon-status/checkrpms.txt");
164: }
165: chmod(0600,"$docroot/lon-status/checkrpms.txt");
166: }
167: system(qq{mail -s '$subj' "$emailto" < $tmpfile});
168: }
169:
170: sub prepare_msg {
171: my ($tmpfile,$cmd) = @_;
172: #
173: # Put some nice text in $tmpfile
174: open(TMPFILE,">>$tmpfile");
175: print TMPFILE <<ENDHEADER;
176: Your system needs to be updated. Please execute (as root)
177:
178: $cmd
179:
180: to bring it up to date.
181:
182: This is very important for the security of your server. The packages which need to be updated are listed below.
183:
184: ENDHEADER
185: close(TMPFILE);
186: return;
187: }
188:
189: sub check_with_you {
190: my ($tmpfile) =@_;
191: my $you = '/usr/bin/online_update';
192: my $sendflag = 0;
193: my $append_to_subj;
194:
195: if (open (PIPE, "$you -k -len 2>&1 |")) {
196: my $output=<PIPE>;
197: close(PIPE);
198: chomp $output;
199: unless ($output eq 'No updates available.') {
200: if (open (PIPE, "$you -s -d -len |grep ^INSTALL |")) {
201: my @updates = <PIPE>;
202: close(PIPE);
203: my $allpackages;
204: foreach my $line (@updates) {
205: my $package = substr($line,rindex($line,'/')+1);
206: if ($package ne '') {
207: $allpackages .= $package;
208: }
209: }
210: if ($allpackages ne '') {
211: open(TMPFILE,">>$tmpfile");
212: print TMPFILE $allpackages;
213: close(TMPFILE);
214: $sendflag = 1;
215: $append_to_subj = ' RPMS to upgrade';
216: }
217: } else {
218: $sendflag = 1;
219: $append_to_subj = ' Error running RPM update script';
220: }
221: }
222: } else {
223: $sendflag = 1;
224: $append_to_subj = ' Error running RPM update script';
225: }
226: return ($sendflag,$append_to_subj);
227: }
228:
229: sub check_with_yum {
230: my ($tmpfile) = @_;
231: my $yum = '/usr/bin/yum';
232: my $sendflag = 0;
233: my $append_to_subj;
234:
235: #
236: # Execute yum command
237: my $command = $yum.' check-update '.'>>'.$tmpfile;
238: system($command);
239:
240: my $returnvalue = $?>>8;
241:
242: #
243: # Determine status of yum run
244: if (100 == $returnvalue) {
245: $sendflag = 1;
246: $append_to_subj = ' RPMS to upgrade';
247: } elsif (0 != $returnvalue) {
248: $sendflag = 1;
249: $append_to_subj = ' Error running RPM update script';
250: } else {
251: # yum returned 0, so everything is up to date.
252: }
253: return ($sendflag,$append_to_subj);
254: }
255:
256: sub check_with_dnf {
257: my ($tmpfile) = @_;
258: my $dnf = '/usr/bin/dnf';
259: my $sendflag = 0;
260: my $append_to_subj;
261:
262: #
263: # Execute dnf command
264: my $command = $dnf.' check-update '.'>>'.$tmpfile;
265: system($command);
266:
267: my $returnvalue = $?>>8;
268:
269: #
270: # Determine status of dnf run
271: if (100 == $returnvalue) {
272: $sendflag = 1;
273: $append_to_subj = ' RPMS to upgrade';
274: } elsif (0 != $returnvalue) {
275: $sendflag = 1;
276: $append_to_subj = ' Error running RPM update script';
277: } else {
278: # dnf returned 0, so everything is up to date.
279: }
280: return ($sendflag,$append_to_subj);
281: }
282:
283: sub check_with_up2date {
284: my ($tmpfile) = @_;
285: my $up2date = '/usr/bin/up2date-nox';
286: my $sendflag = 0;
287: my $append_to_subj;
288: #
289: # Execute online_update command to check for updates
290: my $up2date_error = 1;
291: if (open (PIPE, "$up2date -l 2>&1 |")) {
292: my @result=<PIPE>;
293: close(PIPE);
294: my $output;
295: foreach my $line (@result) {
296: if ($line =~ /^The following Packages were marked to be skipped by your configuration:/) {
297: last;
298: } else {
299: $output .= $line;
300: }
301: }
302: if (@result > 0) {
303: if ($output =~ /Fetching Obsoletes list/) {
304: $up2date_error = 0;
305: if ($output =~ /Name\s+Version\s+Rel\s+[\n\r\f]+\-+[\n\r\f]+(.+)/s) {
306: my $packagelist = $1;
307: if ($packagelist ne '' && $packagelist !~ /^[\s\n\r\f]+$/) {
308: open(TMPFILE,">>$tmpfile");
309: print TMPFILE $packagelist;
310: close(TMPFILE);
311: $append_to_subj = ' RPMS to upgrade';
312: $sendflag = 1;
313: }
314: }
315: }
316: }
317: }
318: if ($up2date_error) {
319: $append_to_subj = ' Error running RPM update script';
320: $sendflag = 1;
321: }
322: return ($sendflag,$append_to_subj);
323: }
324:
325: sub check_with_rug {
326: my ($tmpfile) = @_;
327: my $rug = '/usr/bin/rug';
328: my $sendflag = 0;
329: my $append_to_subj;
330: #
331: # Execute rug command to check for updates
332: if (open (PIPE, "$rug up -N 2>&1 |")) {
333: my @output=<PIPE>;
334: close(PIPE);
335: chomp(@output);
336: my @clean_output;
337: foreach my $line (@output) {
338: if ($line =~ /^Waking\sup\sZMD\.\.\./) {
339: next;
340: } elsif ($line eq 'Done') {
341: next;
342: } elsif ($line eq '') {
343: next;
344: } elsif ($line eq 'The following packages will be installed:') {
345: next;
346: } elsif ($line eq 'Resolving Dependencies...') {
347: next;
348: } elsif ($line eq 'Transaction...') {
349: last;
350: } elsif ($line eq 'No updates are available.') {
351: last;
352: } elsif ($line eq 'Downloading Packages...') {
353: last;
354: } else {
355: push(@clean_output,$line);
356: }
357: }
358: if (@clean_output > 0) {
359: open(TMPFILE,">>$tmpfile");
360: print TMPFILE join("\n",@clean_output);
361: close(TMPFILE);
362: $append_to_subj= ' RPMS to upgrade';
363: $sendflag = 1;
364: }
365: } else {
366: $append_to_subj = ' Error running RPM update check';
367: $sendflag = 1;
368: }
369: return ($sendflag,$append_to_subj);
370: }
371:
372: sub check_with_zypper {
373: my ($tmpfile) = @_;
374: my $zypper = '/usr/bin/zypper';
375: my $sendflag = 0;
376: my $append_to_subj;
377: my $header;
378: #
379: # Execute zypper command to check for updates
380: if (open (PIPE, "$zypper lu 2>&1 |")) {
381: my @output=<PIPE>;
382: close(PIPE);
383: chomp(@output);
384: my @clean_output;
385: foreach my $line (@output) {
386: if ($line eq 'Restoring system sources...') {
387: next;
388: } elsif ($line =~ /^Parsing\smetadata\sfor\s/) {
389: next;
390: } elsif ($line eq 'Parsing RPM database...') {
391: next;
392: } elsif ($line =~ /^Catalog\s+\|\s+Name\s+\|\s+Version\s+\|\s+Category\s+\|\s+Status$/) {
393: $header = $line."\n";
394: next;
395: } elsif ($line =~ /^[-+]+$/) {
396: $header .= $line."\n";
397: next;
398: } elsif ($line eq 'WARNING: These are only the updates affecting the updater itself.') {
399: next;
400: } elsif ($line eq 'There are others available too.') {
401: next;
402: } else {
403: push(@clean_output,$line);
404: }
405: }
406: if (@clean_output > 0) {
407: open(TMPFILE,">>$tmpfile");
408: my $message = join("\n",@clean_output);
409: print TMPFILE $header.$message;
410: close(TMPFILE);
411: $append_to_subj= ' RPMS to upgrade';
412: $sendflag = 1;
413: }
414: } else {
415: $append_to_subj = ' Error running RPM update check';
416: $sendflag = 1;
417: }
418: return ($sendflag,$append_to_subj);
419: }
420:
421: sub check_with_apt {
422: my ($tmpfile) = @_;
423: my $apt = '/usr/bin/apt-get';
424: my $sendflag = 0;
425: my $append_to_subj;
426: my $header;
427: my @chg_package;
428: #
429: # Execute apt-get command to update distributions
430: system ("$apt update > /dev/null");
431: my $returnvalue = $?>>8;
432: if ($returnvalue == 0) {
433: # Execute apt-get commands to check for upgrades
434: if (open (PIPE, "$apt -y --dry-run upgrade 2>&1 |")) {
435: my @output=<PIPE>;
436: close(PIPE);
437: chomp(@output);
438: foreach my $line (@output) {
439: $line =~ s/^\s+//;
440: my @items = split(/\s+/,$line);
441: if ($items[0] eq "Inst") {
442: push(@chg_package,$items[1]);
443: }
444: }
445: if (@chg_package > 0) {
446: $header = 'apt-get upgrade found the following packages need updating:'.
447: "\n\n";
448: open(TMPFILE,">>$tmpfile");
449: my $message = join("\n",@output);
450: print TMPFILE $header.$message;
451: close(TMPFILE);
452: $append_to_subj= ' deb packages to upgrade';
453: $sendflag = 1;
454: }
455: } else {
456: $append_to_subj = ' Error running deb upgrade check';
457: $sendflag = 1;
458: }
459: } else {
460: $append_to_subj = ' Error running deb update check';
461: $sendflag = 1;
462: }
463: return ($sendflag,$append_to_subj);
464: }
465:
466: sub check_with_checkrpms {
467: my ($tmpfile,$perlvar) = @_;
468: my $checkrpms = '/usr/local/bin/check-rpms';
469: my $sendflag = 0;
470: my $append_to_subj;
471:
472: # Run Martin Seigert's checkrpms script. See
473: # See http://www.sfu.ca/acs/security/linux/check-rpms.html
474: # for more information.
475:
476: #
477: # Check that checkrpms is installed and is the proper version...
478: if (! -e $checkrpms) {
479: open(TMPFILE,">>$tmpfile");
480: print TMPFILE <<END;
481:
482: Unable to locate check-rpms on your system. Please go to
483: http://www.sfu.ca/acs/security/linux/check-rpms.html, download and
484: install check-rpms on this system.
485:
486: END
487: $append_to_subj = ' Error running RPM update check';
488: $sendflag = 1;
489: } else {
490: #
491: # Run check-rpms and capture its output
492: if (open (PIPE, "$checkrpms 2>&1 |")) {
493: my $output=<PIPE>;
494: close(PIPE);
495: if ($output ne '') {
496: $output = <<"END";
497:
498: checkrpms checked the status of the packages on your system and
499: produced the following output:
500: -------------------------------------------------------
501: $output
502: -------------------------------------------------------
503: If there are rpms which need to be installed, please log into
504: $perlvar->{'lonHostID'} and run the following command
505:
506: $checkrpms --update
507:
508: If there are kernel packages to be installed, use
509:
510: $checkrpms --update --install-kernel
511:
512: Keeping your system up to date is very important.
513: Ensuring you are using up to date software is a prerequisite for a
514: secure system.
515:
516: END
517: open(TMPFILE,">>$tmpfile");
518: print TMPFILE $output;
519: close(TMPFILE);
520: $append_to_subj = ' RPMS to upgrade';
521: $sendflag = 1;
522: }
523: }
524: }
525: return ($sendflag,$append_to_subj);
526: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>