[project @ peter@palfrader.org-20080519135700-ekglreng7ttedbqd]
authorPeter Palfrader <peter@palfrader.org>
Mon, 19 May 2008 13:57:00 +0000 (15:57 +0200)
committerPeter Palfrader <peter@palfrader.org>
Mon, 19 May 2008 13:57:00 +0000 (15:57 +0200)
* Add dsa-check-statusfile.
* Add weak-ssh-keys-check to be run from cron.daily.  Depend on
  libberkeleydb-perl and dsa-ssh-weak-keys now.
* Remove up /var/cache/dsa/nagios/weak-ssh-keys in postrm purge.

dsa-nagios-nrpe-config/debian/changelog
dsa-nagios-nrpe-config/debian/control
dsa-nagios-nrpe-config/debian/copyright
dsa-nagios-nrpe-config/debian/cron.daily [new file with mode: 0644]
dsa-nagios-nrpe-config/debian/dirs
dsa-nagios-nrpe-config/debian/postrm [new file with mode: 0644]
dsa-nagios-nrpe-config/debian/rules
dsa-nagios-nrpe-config/dsa-check-statusfile [new file with mode: 0755]
dsa-nagios-nrpe-config/weak-ssh-keys-check [new file with mode: 0755]

index 6271668..8f21cff 100644 (file)
@@ -1,3 +1,12 @@
+dsa-nagios-nrpe-config (41) unstable; urgency=low
+
+  * Add dsa-check-statusfile.
+  * Add weak-ssh-keys-check to be run from cron.daily.  Depend on
+    libberkeleydb-perl and dsa-ssh-weak-keys now.
+  * Remove up /var/cache/dsa/nagios/weak-ssh-keys in postrm purge.
+
+ -- Peter Palfrader <weasel@debian.org>  Mon, 19 May 2008 15:55:43 +0200
+
 dsa-nagios-nrpe-config (40) unstable; urgency=low
 
   * Teach dsa-check-hpacucli about rebuilding.
 dsa-nagios-nrpe-config (40) unstable; urgency=low
 
   * Teach dsa-check-hpacucli about rebuilding.
index dad9749..14e8564 100644 (file)
@@ -7,7 +7,7 @@ Standards-Version: 3.7.2
 
 Package: dsa-nagios-nrpe-config
 Architecture: all
 
 Package: dsa-nagios-nrpe-config
 Architecture: all
-Depends: nagios-nrpe-server, nagios-plugins-basic, ${misc:Depends}, binutils
+Depends: nagios-nrpe-server, nagios-plugins-basic, ${misc:Depends}, binutils, libberkeleydb-perl, dsa-ssh-weak-keys
 Suggests: hpacucli
 Description: debian.org nagios-nrpe-server configuration
  This package provides the debian.org configuration for the
 Suggests: hpacucli
 Description: debian.org nagios-nrpe-server configuration
  This package provides the debian.org configuration for the
index 28c92c2..e956f83 100644 (file)
@@ -32,3 +32,13 @@ dsa-check-running-kernel:
 dsa-check-hpacucli:
   Copyright: 2008 Peter Palfrader
   License: MIT
 dsa-check-hpacucli:
   Copyright: 2008 Peter Palfrader
   License: MIT
+
+########################################################################
+dsa-check-statusfile:
+  Copyright: 2008 Peter Palfrader
+  License: MIT
+
+########################################################################
+weak-ssh-keys-check:
+  Copyright: 2008 Florian Weimer, Alexander Wirt
+  License: ISC
diff --git a/dsa-nagios-nrpe-config/debian/cron.daily b/dsa-nagios-nrpe-config/debian/cron.daily
new file mode 100644 (file)
index 0000000..c37e41e
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+[ -x /usr/share/dsa/weak-ssh-keys-check ] && /usr/share/dsa/weak-ssh-keys-check -s /var/cache/dsa/nagios/weak-ssh-keys
index 775d720..2e42e42 100644 (file)
@@ -1,2 +1,4 @@
 etc/nagios
 usr/lib/nagios/plugins
 etc/nagios
 usr/lib/nagios/plugins
+usr/share/dsa
+var/cache/dsa/nagios
diff --git a/dsa-nagios-nrpe-config/debian/postrm b/dsa-nagios-nrpe-config/debian/postrm
new file mode 100644 (file)
index 0000000..272a7cc
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/sh
+# postrm script for dsa-ssh-weak-keys
+#
+# see: dh_installdeb(1)
+
+set -e
+
+case "$1" in
+    purge)
+       rm -f /var/cache/dsa/nagios/weak-ssh-keys
+    ;;
+    remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
+    ;;
+
+    *)
+        echo "postrm called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+#DEBHELPER#
+
+exit 0
index 691a753..cad941f 100755 (executable)
@@ -24,12 +24,15 @@ install:
        install -m 755 dsa-check-dabackup $(CURDIR)/debian/dsa-nagios-nrpe-config/usr/lib/nagios/plugins
        install -m 755 dsa-check-udldap-freshness $(CURDIR)/debian/dsa-nagios-nrpe-config/usr/lib/nagios/plugins
 
        install -m 755 dsa-check-dabackup $(CURDIR)/debian/dsa-nagios-nrpe-config/usr/lib/nagios/plugins
        install -m 755 dsa-check-udldap-freshness $(CURDIR)/debian/dsa-nagios-nrpe-config/usr/lib/nagios/plugins
 
+       install -m 755 weak-ssh-keys-check $(CURDIR)/debian/dsa-nagios-nrpe-config/usr/share/dsa/weak-ssh-keys-check
+
 
 binary-indep: install
        dh_testdir
        dh_testroot
 
 binary-indep: install
        dh_testdir
        dh_testroot
-       dh_installchangelogs 
+       dh_installchangelogs
        dh_installdocs
        dh_installdocs
+       dh_installcron
        dh_compress
        dh_fixperms
        dh_installdeb
        dh_compress
        dh_fixperms
        dh_installdeb
diff --git a/dsa-nagios-nrpe-config/dsa-check-statusfile b/dsa-nagios-nrpe-config/dsa-check-statusfile
new file mode 100755 (executable)
index 0000000..a69d977
--- /dev/null
@@ -0,0 +1,81 @@
+#!/usr/bin/ruby
+
+# Relay the status of a check that was previously run and which stored
+# its result in a file to nagios.
+#
+# Copyright 2008 Peter Palfrader
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+require 'resolv'
+require 'optparse'
+
+NAGIOS_STATUS = { "OK" => 0, "WARNING" => 1, "CRITICAL" => 2, "UNKNOWN" => 3 }
+UNITS_TO_SECONDS = { 's' => 1, 'm' => 60, 'h' => 60*60, 'd' => 24*60*60 }
+
+def show_help(parser, code=0, io=STDOUT)
+  program_name = File.basename($0, '.*')
+  io.puts "Usage: #{program_name} [options] <statusfile>"
+  io.puts parser.summarize
+  exit(code)
+end
+
+max_age = "26h"
+ARGV.options do |opts|
+        opts.on_tail("-h", "--help" , "Display this help screen")                                               { show_help(opts) }
+        opts.on("-a", "--age=AGE"  , String, "maximum age, in seconds (or use Nm, Nh or Nd) - default is 26h")  { |max_age| }
+        opts.parse!
+end
+show_help(ARGV.options, 1, STDERR) if ARGV.length != 1
+
+statusfile = ARGV.shift
+
+# find out what the max age is that we accept
+unless (m = /^([0-9]+)([smhd])?$/.match max_age)
+       STDERR.puts "Invalid age #{age}."
+       show_help(ARGV.options, 1, STDERR) if ARGV.length != 1
+end
+max_age = m[1].to_i * UNITS_TO_SECONDS[m[2] ? m[2] : 's']
+
+# let's see if it exists
+unless File.exists? statusfile
+       puts "UNKNOWN: #{statusfile} does not exist."
+       exit NAGIOS_STATUS['UNKNOWN']
+end
+
+
+mtime = File.stat(statusfile).mtime
+if mtime + max_age < Time.now
+       puts "WARNING: #{statusfile} is old: #{mtime}"
+       exit NAGIOS_STATUS['WARNING']
+end
+
+status = File.new(statusfile)
+returnvalue = status.readline.chomp
+
+unless NAGIOS_STATUS.has_key? returnvalue
+       puts "UNKNOWN: #{statusfile} has invalid return value: #{returnvalue}"
+       exit NAGIOS_STATUS['UNKNOWN']
+end
+
+status.readlines.each do |line|
+       print line
+end
+exit NAGIOS_STATUS[returnvalue]
diff --git a/dsa-nagios-nrpe-config/weak-ssh-keys-check b/dsa-nagios-nrpe-config/weak-ssh-keys-check
new file mode 100755 (executable)
index 0000000..3e07842
--- /dev/null
@@ -0,0 +1,290 @@
+#!/usr/bin/perl
+
+# This cheak is based on code from the Debian/OpenSSL Weak Key Detector
+# written by Florian Weimer <fw@deneb.enyo.de>. 
+# The code has been modified and enhanced by Alexander Wirt 
+# <formorer@debian.org> to use it as a nagios check. 
+#
+# Copyright (c) 2008, Florian Weimer <fw@deneb.enyo.de> for the original 
+# Debian/OpenSSL Weak Key Detector 
+# (http://security.debian.org/project/extra/dowkd/dowkd.pl.gz)
+#
+# Copyright (c) 2008, Alexander Wirt <formorer@debian.org> for check_weakkeys
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+=pod
+
+=head1 NAME
+
+B<check_weakkeys> - checks system for weak ssh keys 
+
+=cut
+
+=head1 SYNOPSIS
+
+B<check_weakkeys> [options]
+
+=cut
+
+=head1 DESCRIPTION
+
+B<check_weakkeys> checks for all users if there id_rsa, id_dsa or
+authorized_key files if they contain weak ssh keys created by a Debian with a
+broken libssl (see DSA-1571 for more informations). Optionally <check_weakkeys>
+can spit out a warning of there are any DSA keys left in key or authorized_key
+files. To work it needs a database of precomputed hashes of known weak keys.
+This file is expected as an bdb database with the hash (like
+03:a2:f0:46:7f:13:9f:5f:96:71:a9:b8:a0:1c:01:05) as key. See <gen_fprdb> for
+such a database generator.  <check_weakkeys> outputs his data to STDOUT or to a
+file. It meaned to be picked up by an nagios check like B<dsa-check-statusfile>
+from Peter Palfrader. 
+
+=cut
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-h, --help>
+
+Prints out a brief help
+
+=item B<-s, --statusfile> "statusfile"
+
+Use 'F<statusfile>' instead of 'F<STDOUT>'. 
+
+=item B<-f, --fprdb> "database" (default: /var/lib/dsa/ssh-weak-keys.db)
+
+Use 'F<database>' instead of 'F</var/lib/dsa/ssh-weak-keys.db>'
+as fingerprint database. 
+
+=item B<-n, --dsa_nowarn> 
+
+Don't warn for DSA keys
+
+=back 
+
+=cut
+
+use strict;
+use warnings;
+
+use File::Temp;
+use BerkeleyDB;
+use Pod::Usage;
+use Getopt::Long;
+use IPC::Open3;
+
+my $fprdb_fname = "/var/lib/dsa/ssh-weak-keys.db" ;
+my ($outfile, $help);
+my $dsa_nowarn = 0;
+
+GetOptions(     'help|h' => \$help, #Help function
+               'statusfile|s=s' => \$outfile, 
+               'fprdb|f=s' => \$fprdb_fname,
+               'n|dsa_nowarn' => \$dsa_nowarn,  
+);
+
+pod2usage(1) if $help;
+
+my $fh; 
+if ($outfile) {
+       open ($fh, '>', $outfile) 
+               or die "Could not open statusfile '$outfile' for writing: $!";
+} else {
+       $fh = *STDOUT; 
+}
+
+my %fpr_hash;
+tie %fpr_hash, 'BerkeleyDB::Btree',
+       -Filename   => $fprdb_fname,
+       -Flags      => DB_RDONLY
+               or die "Cannot open fingerprint db $fprdb_fname: $! $BerkeleyDB::Error\n";
+
+
+my ($weak_keys,$checked_keys) = 0;
+my $dsa_keys = 0;
+my $text = '';
+my %key_sizes;
+
+
+
+&from_user_all;
+&from_ssh_host(qw(localhost));
+
+my $status="OK";
+if ($weak_keys) {
+       $status = "CRITICAL";
+} elsif ($dsa_keys && ! $dsa_nowarn) {
+       $status = "WARNING";
+}
+
+print $fh "$status\n";
+print $fh "Checked $checked_keys keys - $weak_keys weak - $dsa_keys dsa keys\n";
+print $fh "Sizes: ";
+foreach my $size (sort(keys(%key_sizes))) {
+       print $fh "$size:$key_sizes{$size} ";
+}
+
+print $fh "\n";
+print $fh "$text" if $text;
+
+
+
+sub safe_backtick (@) {
+    my @args = @_;
+
+    my ($wtr, $fh, $err);
+
+    open3($wtr,$fh,$err, @args)
+       or die "error: failed to spawn $args[0]: $!\n";
+    my @result;
+    if (wantarray) {
+       @result = <$fh>;
+    } else {
+       local $/;
+       @result = scalar(<$fh>);
+    }
+    close $fh;
+    $? == 0 or return undef;
+    if (wantarray) {
+       return @result;
+    } else {
+       return $result[0];
+    }
+}
+
+sub ssh_fprint_file ($) {
+    my $name = shift;
+    my $data = safe_backtick qw/ssh-keygen -l -f/, $name;
+    defined $data or return ();
+    my @data = $data =~ /^(\d+) ([0-9a-f]{2}(?::[0-9a-f]{2}){15})/;
+    return @data if @data == 2;
+    return ();
+}
+
+sub ssh_fprint_check ($$$) {
+    my ($name, $length, $hash) = @_;
+    if (exists $key_sizes{$length}) {
+           $key_sizes{$length}++;
+    } else {
+           $key_sizes{$length}=1;
+    }
+    $checked_keys++;
+    if (exists $fpr_hash{$hash}) {
+       $weak_keys++;
+       $text .= "$name weak ($hash)\n";
+    }
+}
+
+
+sub from_ssh_key_file ($) {
+    my $name = shift;
+    if (open (my $FH, '<', $name)) {
+       my $key = <$FH>; 
+       if ($key =~ m/^ssh-dss/) {
+               $dsa_keys++;
+               $text .= "$name is a DSA key\n";
+       }
+    } else {
+       $text .= "Could not open $name: $!";
+    }
+    my ($length, $hash) = ssh_fprint_file $name;
+    if ($length && $hash) {
+       ssh_fprint_check "$name:1", $length, $hash;
+    } else {
+       $text .= "$name:1: warning: failed to parse SSH key file\n";
+    }
+}
+
+sub clear_tmp ($) {
+    my $tmp = shift;
+    seek $tmp, 0, 0 or die "seek: $!";
+    truncate $tmp, 0 or die "truncate: $!";
+}
+
+sub from_ssh_auth_file ($) {
+    my $name = shift;
+    my $auth;
+    unless (open $auth, '<', $name) {
+       warn "$name:0: error: open failed: $!\n";
+       return;
+    }
+    my $tmp = new File::Temp;
+    while (my $line = <$auth>) {
+       chomp $line;
+       my $lineno = $.;
+       clear_tmp $tmp;
+       next if $line =~ m/^#/; # ignore comments
+       if ($line =~ m/^ssh-dss/) {
+               $dsa_keys++;
+               $text .= "$name:$lineno is a DSA key\n";
+       }
+       print $tmp "$line\n" or die "print: $!";
+       $tmp->flush;
+       my ($length, $hash) = ssh_fprint_file "$tmp";
+       if ($length && $hash) {
+           ssh_fprint_check "$name:$lineno", $length, $hash;
+       } else {
+           $text .= "$name:$lineno: warning: unparsable line\n";
+       }
+    }
+}
+
+sub from_ssh_host (@) {
+    my @names = @_;
+    my @lines;
+    push @lines, safe_backtick qw|ssh-keyscan -t rsa|, @names;
+    push @lines, safe_backtick qw|ssh-keyscan -t dsa|, @names;
+
+    my $tmp = new File::Temp;
+    for my $line (@lines) {
+       next if $line =~ /^#/;
+       my ($host, $data) = $line =~ /^(\S+) (.*)$/;
+       clear_tmp $tmp;
+       print $tmp "$data\n" or die "print: $!";
+       $tmp->flush;
+       my ($length, $hash) = ssh_fprint_file "$tmp";
+       if ($length && $hash) {
+           ssh_fprint_check "$host", $length, $hash;
+       } else {
+           $text .= "$host: warning: unparsable line\n";
+       }
+    }
+}
+
+sub from_user ($) {
+    my $user = shift;
+    my ($name,$passwd,$uid,$gid,
+       $quota,$comment,$gcos,$dir,$shell,$expire) = getpwnam($user);
+    my $file = "$dir/.ssh/authorized_keys";
+    from_ssh_auth_file $file if -r $file;
+    $file = "$dir/.ssh/authorized_keys2";
+    from_ssh_auth_file $file if -r $file;
+    $file = "$dir/.ssh/id_rsa.pub";
+    from_ssh_key_file $file if -r $file;
+    $file = "$dir/.ssh/id_dsa.pub";
+    from_ssh_key_file $file if -r $file;
+}
+
+sub from_user_all () {
+    setpwent;
+    while (my $name = getpwent) {
+       from_user $name;
+    }
+    endpwent;
+}
+
+