Procházet zdrojové kódy

Merge remote-tracking branch 'upstream/master'

Conflicts:
	plugins/netutils.c
Greg Cox před 12 roky
rodič
revize
4273dd06ff
72 změnil soubory, kde provedl 1132 přidání a 487 odebrání
  1. 13 2
      .travis.yml
  2. 33 7
      NEWS
  3. 1 1
      NP-VERSION-GEN
  4. 29 5
      NPTest.pm
  5. 7 5
      REQUIREMENTS
  6. 18 0
      THANKS.in
  7. 14 9
      configure.ac
  8. 9 1
      gl/Makefile.am
  9. 204 0
      gl/idpriv-droptemp.c
  10. 116 0
      gl/idpriv.h
  11. 2 1
      gl/m4/gnulib-cache.m4
  12. 7 2
      gl/m4/gnulib-comp.m4
  13. 14 0
      gl/m4/idpriv.m4
  14. 261 231
      lib/parse_ini.c
  15. 1 41
      lib/parse_ini.h
  16. 6 2
      lib/tests/test_utils.c
  17. 3 14
      lib/utils_base.c
  18. 0 3
      lib/utils_base.h
  19. 3 0
      lib/utils_cmd.c
  20. 1 4
      plugins-root/check_dhcp.c
  21. 0 3
      plugins-root/check_icmp.c
  22. 2 1
      plugins-scripts/Makefile.am
  23. 1 0
      plugins-scripts/check_breeze.pl
  24. 1 0
      plugins-scripts/check_disk_smb.pl
  25. 3 1
      plugins-scripts/check_file_age.pl
  26. 1 0
      plugins-scripts/check_flexlm.pl
  27. 1 0
      plugins-scripts/check_ifoperstatus.pl
  28. 2 1
      plugins-scripts/check_ifstatus.pl
  29. 1 0
      plugins-scripts/check_ircd.pl
  30. 1 0
      plugins-scripts/check_mailq.pl
  31. 3 1
      plugins-scripts/check_mssql.pl
  32. 1 0
      plugins-scripts/check_netdns.pl
  33. 1 0
      plugins-scripts/check_rpc.pl
  34. 1 0
      plugins-scripts/check_wave.pl
  35. 3 0
      plugins/check_apt.c
  36. 3 3
      plugins/check_dbi.c
  37. 17 1
      plugins/check_dns.c
  38. 24 6
      plugins/check_hpjd.c
  39. 6 4
      plugins/check_http.c
  40. 1 1
      plugins/check_ide_smart.c
  41. 1 1
      plugins/check_mrtg.c
  42. 20 2
      plugins/check_mysql.c
  43. 2 2
      plugins/check_nt.c
  44. 11 2
      plugins/check_ntp.c
  45. 37 12
      plugins/check_ntp_peer.c
  46. 12 3
      plugins/check_ntp_time.c
  47. 28 21
      plugins/check_radius.c
  48. 1 0
      plugins/check_real.c
  49. 20 4
      plugins/check_ssh.c
  50. 8 4
      plugins/check_tcp.c
  51. 3 3
      plugins/check_ups.c
  52. 5 6
      plugins/negate.c
  53. 12 3
      plugins/netutils.c
  54. 2 2
      plugins/netutils.h
  55. 1 1
      plugins/runcmd.c
  56. 6 5
      plugins/sslutils.c
  57. 56 0
      plugins/t/NPTest.cache.travis
  58. 2 1
      plugins/t/check_dns.t
  59. 8 6
      plugins/t/check_fping.t
  60. 28 7
      plugins/t/check_hpjd.t
  61. 3 3
      plugins/t/check_jabber.t
  62. 7 7
      plugins/t/check_ntp.t
  63. 1 1
      plugins/t/check_procs.t
  64. 1 1
      plugins/t/check_snmp.t
  65. 1 1
      plugins/t/check_udp.t
  66. 15 20
      plugins/tests/check_http.t
  67. 17 12
      plugins/tests/check_procs.t
  68. 1 1
      plugins/tests/check_snmp.t
  69. 2 2
      po/de.po
  70. 2 2
      po/fr.po
  71. 2 2
      po/monitoring-plugins.pot
  72. 2 0
      test.pl.in

+ 13 - 2
.travis.yml

@@ -1,19 +1,30 @@
 language: c
 
 before_install:
+  - sudo add-apt-repository -y ppa:waja/precise-backports
   - sudo apt-get update -qq
   - sudo apt-get purge -qq gawk
 
 install:
-  - sudo apt-get install -qq --no-install-recommends perl autotools-dev libdbi-dev libldap2-dev libpq-dev libmysqlclient-dev libradiusclient-ng-dev libkrb5-dev libnet-snmp-perl procps
+  - sudo apt-get install -qq --no-install-recommends perl autotools-dev libdbi-dev libldap2-dev libpq-dev libmysqlclient-dev libfreeradius-client-dev libkrb5-dev libnet-snmp-perl procps
+  - sudo apt-get install -qq --no-install-recommends libdbi0-dev libdbd-sqlite3 libssl-dev dnsutils snmp-mibs-downloader
+  - sudo apt-get install -qq --no-install-recommends fping snmp netcat smbclient fping pure-ftpd apache2 postfix libhttp-daemon-ssl-perl
   - sudo apt-get install -qq --no-install-recommends autoconf automake
 
 before_script:
   - tools/setup
   - ./configure
+  - make
+  - export NPTEST_CACHE="$(pwd)/plugins/t/NPTest.cache.travis"
+  - ssh-keygen -t dsa -N "" -f ~/.ssh/id_dsa
+  - cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys
+  - ssh-keyscan localhost >> ~/.ssh/known_hosts
+  - touch ~/.ssh/config
+  - sudo rm -f /usr/share/mibs/ietf/SNMPv2-PDU /usr/share/mibs/ietf/IPSEC-SPD-MIB /usr/share/mibs/ietf/IPATM-IPMC-MIB /usr/share/mibs/iana/IANA-IPPM-METRICS-REGISTRY-MIB
+  - sudo mkdir -p /var/lib/snmp/mib_indexes
 
 script:
-  - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make; fi
+  - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make test; fi
 
 notifications:
   irc:

+ 33 - 7
NEWS

@@ -1,28 +1,54 @@
 This file documents the major additions and syntax changes between releases.
 
-1.6 ...
+2.1
 	ENHANCEMENTS
-        check_mailq now supports auto detection of qmail, postfix, exim and nullmailer with
-          fallback to sendmail
+	New check_hpjd -p option for port specification (abrist)
+
+2.0 11th July 2014
+	ENHANCEMENTS
+	check_mailq now supports auto detection of qmail, postfix, exim and nullmailer with
+	  fallback to sendmail
 	check_ide_smart now defaults to plugin output, original output appended with -v
-	Extra-Opts are now enabled by default
+	Extra-Opts are now enabled by default, see:
+	  https://www.monitoring-plugins.org/doc/extra-opts.html
 	check_swap now supports a configurable state when there is no swap
+	check_radius now supports the FreeRADIUS Client library
+	New check_mysql_query -f option to specify a client options file
+	New check_mysql_query -g option to specify a client options group
+	Add performance data to check_mysql_query
+	New check_file_age -i/--ignore-missing option to return OK on nonexistent files
+	Make check_ping, check_users, and check_disk work on Windows
+	New check_ssh -P option to specify the expected SSH protocol version
+	check_dns now emits the warning and critical thresholds with the performance data
 
 	FIXES
 	Don't let e.g. check_http's -C option reset SSL version if e.g. -S 1 -C 5 is specified
+	Don't have check_http's -N option expect an argument
 	check_ide_smart could disable offline auto tests but could not re-enable them.
 	  For this reason all SMART command modes have been disabled.
 	check_dig: fix wrong IPv6 arguments order (Stéphane Bortzmeyer)
+	check_dig: make sure not to give up too early when a timeout is specified with -t
+	check_log: don't stumble over log lines that include a "%" character
+	check_nt: add UPTIME to perfdata
+	Handle SNMPv3 noAuthNoPriv properly with check_snmp
+	Fix compilation with GnuTLS
 
 	WARNINGS
-	check_procs now ignores its parent process to avoid unexpected results when invoked via certain shells
+	New default installation prefix: /usr/local instead of /usr/local/nagios
+	check_snmp now evaluates negative values properly, which means it might return CRITICAL
+	  in cases where it used to return OK. If this is undesired, the warning/critical
+	  threshold(s) must be fixed by specifying e.g. ~:100 instead of 100
+	check_procs now ignores its parent process to avoid unexpected results when invoked via
+	  certain shells
 	utils.sh no longer defines ECH
-	check_ide_smart -q/--quiet and -n/--nagios (Nagios-compatile output) are now deprecated
+	check_ide_smart -q/--quiet and -n/--nagios (Nagios-compatible output) are now deprecated
 	  but accepted for backward-compatibility
 	check_ide_smart -0/--auto-off, -1/--auto-on and -i/--immediate: options have
 	  been disabled because they were broken
 	State retention: the NAGIOS_PLUGIN_STATE_DIRECTORY environment variable has been
-	  renamed MP_STATE_DIRECTORY. The old variable will continue to work in v1.6.x
+	  renamed MP_STATE_PATH. The old variable will continue to work in v2.0.x
+	Add the UID of the invoking user to the state retention file path. This helps solving
+	  permission issues when different users run the same plugin
 	check_swap used to allow returning OK on a system without swap when only percent thresholds
 	  were used. This is no longer the case and one must now use -n/--no-swap=<state>
 	The Perl and Shell plugins now use the PATH specified via ./configure's --trusted-path

+ 1 - 1
NP-VERSION-GEN

@@ -6,7 +6,7 @@
 SRC_ROOT=`dirname $0`
 
 NPVF=NP-VERSION-FILE
-DEF_VER=1.5.git
+DEF_VER=2.0.git
 
 LF='
 '

+ 29 - 5
NPTest.pm

@@ -6,7 +6,7 @@ package NPTest;
 
 require Exporter;
 @ISA       = qw(Exporter);
-@EXPORT    = qw(getTestParameter checkCmd skipMissingCmd);
+@EXPORT    = qw(getTestParameter checkCmd skipMissingCmd skipMsg);
 @EXPORT_OK = qw(DetermineTestHarnessDirectory TestsFrom SetCacheFilename);
 
 use strict;
@@ -38,8 +38,8 @@ testing.
 
 =head1 FUNCTIONS
 
-This module defines three public functions, C<getTestParameter(...)>,
-C<checkCmd(...)> and C<skipMissingCmd(...)>.  These are exported by
+This module defines four public functions, C<getTestParameter(...)>,
+C<checkCmd(...)>, C<skipMissingCmd(...)> and C<skipMsg(...)>.  These are exported by
 default via the C<use NPTest;> statement.
 
 =over
@@ -185,6 +185,15 @@ of times.
 
 =back
 
+=item C<skipMsg(...)>
+
+If for any reason the test harness must C<Test::skip()> some
+or all of the tests in a given test harness this function provides a
+simple iterator to issue an appropriate message the requested number
+of times.
+
+=back
+
 =head1 SEE ALSO
 
 L<Test>
@@ -304,6 +313,20 @@ sub skipMissingCmd
   return $testStatus;
 }
 
+sub skipMsg
+{
+  my( $msg, $count ) = @_;
+
+  my $testStatus;
+
+  for ( 1 .. $count )
+  {
+    $testStatus += skip( $msg, 1 );
+  }
+
+  return $testStatus;
+}
+
 sub getTestParameter
 {
   my( $param, $envvar, $default, $brief, $scoped );
@@ -627,12 +650,13 @@ sub only_output {
 }
 
 sub testCmd {
-	my $class = shift;
+	my $class   = shift;
 	my $command = shift or die "No command passed to testCmd";
+	my $timeout = shift || 120;
 	my $object = $class->new;
 
 	local $SIG{'ALRM'} = sub { die("timeout in command: $command"); };
-	alarm(120); # no test should take longer than 120 seconds
+	alarm($timeout); # no test should take longer than 120 seconds
 
 	my $output = `$command`;
 	$object->return_code($? >> 8);

+ 7 - 5
REQUIREMENTS

@@ -50,14 +50,16 @@ check_dbi:
 	  http://libdbi.sourceforge.net/
 
 check_radius:
-	- Requires the radiusclient-ng library available from:
-	  http://developer.berlios.de/projects/radiusclient-ng/
+	- Requires the FreeRADIUS Client library available from:
+	  http://freeradius.org/freeradius-client/
+	- As an alternative, the radiusclient-ng library may be used:
+	  http://sourceforge.net/projects/radiusclient-ng.berlios/
 	- This plugin also works with the original radiusclient library from
 	  ftp://ftp.cityline.net/pub/radiusclient/
 		RPM (rpmfind): radiusclient 0.3.2, radiusclient-devel-0.3.2
-	  Unless you're using a distro-maintained version of this library you
-	  probably want to use radiusclient-ng. The original radiusclient library is
-	  unmaintained and has many known issues, particularly with 64bit systems.
+	  However, you probably want to use the FreeRADIUS Client library, as
+	  both radiusclient and radiusclient-ng are unmaintained and have known
+	  issues.
 
 check_snmp:
 	- Requires the NET-SNMP package available from

+ 18 - 0
THANKS.in

@@ -308,3 +308,21 @@ Luca Corti
 Jethro Carr
 Evgeni Golov
 Oskar Liljeblad
+Andrew Widdersheim
+Anton Lofgren
+Damian Myerscough
+Davide Madrisan
+Gunnar Beutner
+Joseph Gooch
+Lars Vogdt
+Ricardo Maraschini
+Spenser Reinhardt
+Stephane Lapie
+Tilmann Bubeck
+Eric J. Mislivec
+Jean-Claude Computing
+Andy Brist
+Mikael Falkvidd
+Patric Wust
+Julius Kriukas
+Patrick McAndrew

+ 14 - 9
configure.ac

@@ -1,6 +1,6 @@
 dnl Process this file with autoconf to produce a configure script.
 AC_PREREQ(2.59)
-AC_INIT(monitoring-plugins,1.5)
+AC_INIT(monitoring-plugins,2.0)
 AC_CONFIG_SRCDIR(NPTest.pm)
 AC_CONFIG_FILES([gl/Makefile 
 	monitoring-plugins.spec])
@@ -274,20 +274,27 @@ AC_ARG_WITH([radius], [AS_HELP_STRING([--without-radius], [Skips the radius plug
 dnl Check for radius libraries
 AS_IF([test "x$with_radius" != "xno"], [
   _SAVEDLIBS="$LIBS"
-  AC_CHECK_LIB(radiusclient,rc_read_config)
-  if test "$ac_cv_lib_radiusclient_rc_read_config" = "yes"; then
+  AC_CHECK_LIB(freeradius-client,rc_read_config)
+  if test "$ac_cv_lib_freeradius_client_rc_read_config" = "yes"; then
     EXTRAS="$EXTRAS check_radius\$(EXEEXT)"
-  	RADIUSLIBS="-lradiusclient"
+    RADIUSLIBS="-lfreeradius-client"
     AC_SUBST(RADIUSLIBS)
   else
     AC_CHECK_LIB(radiusclient-ng,rc_read_config)
     if test "$ac_cv_lib_radiusclient_ng_rc_read_config" = "yes"; then
       EXTRAS="$EXTRAS check_radius\$(EXEEXT)"
-    	  RADIUSLIBS="-lradiusclient-ng"
+      RADIUSLIBS="-lradiusclient-ng"
       AC_SUBST(RADIUSLIBS)
     else
-      AC_MSG_WARN([Skipping radius plugin])
-      AC_MSG_WARN([install radius libs to compile this plugin (see REQUIREMENTS).])
+      AC_CHECK_LIB(radiusclient,rc_read_config)
+      if test "$ac_cv_lib_radiusclient_rc_read_config" = "yes"; then
+        EXTRAS="$EXTRAS check_radius\$(EXEEXT)"
+        RADIUSLIBS="-lradiusclient"
+        AC_SUBST(RADIUSLIBS)
+      else
+        AC_MSG_WARN([Skipping radius plugin])
+        AC_MSG_WARN([install radius libs to compile this plugin (see REQUIREMENTS).])
+      fi
     fi
   fi
   LIBS="$_SAVEDLIBS"
@@ -509,8 +516,6 @@ dnl check for gnutls if openssl isn't found (or is disabled)
 if test ! "$FOUNDOPENSSL" = "yes" && test ! "$with_gnutls" = "no"; then
 	if test ! "$with_gnutls" = ""; then
 		CPPFLAGS="$CPPFLAGS -I${with_gnutls}/include"
-	elif test ! "$LIBGNUTLS_CONFIG" = ""; then
-		CPPFLAGS="$CPPFLAGS -I`$LIBGNUTLS_CONFIG --prefix`"
 	fi
 	AC_CHECK_HEADERS([gnutls/openssl.h],FOUNDGNUTLS="yes",)
 	if test "$FOUNDGNUTLS" = "yes"; then

+ 9 - 1
gl/Makefile.am

@@ -21,7 +21,7 @@
 # the same distribution terms as the rest of that program.
 #
 # Generated by gnulib-tool.
-# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files base64 crypto/sha1 dirname environ floorf fsusage getaddrinfo gethostname getloadavg getopt-gnu gettext mountlist regex setenv strcase strsep timegm unsetenv vasprintf vsnprintf
+# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files base64 crypto/sha1 dirname environ floorf fsusage getaddrinfo gethostname getloadavg getopt-gnu gettext idpriv-droptemp mountlist regex setenv strcase strsep timegm unsetenv vasprintf vsnprintf
 
 AUTOMAKE_OPTIONS = 1.9.6 gnits subdir-objects
 
@@ -402,6 +402,14 @@ EXTRA_DIST += $(top_srcdir)/build-aux/config.rpath
 
 ## end   gnulib module havelib
 
+## begin gnulib module idpriv-droptemp
+
+libgnu_a_SOURCES += idpriv-droptemp.c
+
+EXTRA_DIST += idpriv.h
+
+## end   gnulib module idpriv-droptemp
+
 ## begin gnulib module inet_ntop
 
 

+ 204 - 0
gl/idpriv-droptemp.c

@@ -0,0 +1,204 @@
+/* Dropping uid/gid privileges of the current process temporarily.
+   Copyright (C) 2009-2013 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+#include "idpriv.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/* The privileged uid and gid that the process had earlier.  */
+#if HAVE_GETUID
+static int saved_uid = -1;
+#endif
+#if HAVE_GETGID
+static int saved_gid = -1;
+#endif
+
+int
+idpriv_temp_drop (void)
+{
+#if HAVE_GETEUID && HAVE_GETEGID && (HAVE_SETRESUID || HAVE_SETREUID) && (HAVE_SETRESGID || HAVE_SETREGID)
+  int uid = getuid ();
+  int gid = getgid ();
+
+  /* Find out about the privileged uid and gid at the first call.  */
+  if (saved_uid == -1)
+    saved_uid = geteuid ();
+  if (saved_gid == -1)
+    saved_gid = getegid ();
+
+  /* Drop the gid privilege first, because in some cases the gid privilege
+     cannot be dropped after the uid privilege has been dropped.  */
+
+  /* This is for executables that have the setgid bit set.  */
+# if HAVE_SETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */
+  if (setresgid (-1, gid, saved_gid) < 0)
+    return -1;
+# else /* Mac OS X, NetBSD, AIX, IRIX, Solaris >= 2.5, OSF/1, Cygwin */
+  if (setregid (-1, gid) < 0)
+    return -1;
+# endif
+
+  /* This is for executables that have the setuid bit set.  */
+# if HAVE_SETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */
+  /* See <http://www.usenix.org/events/sec02/full_papers/chen/chen.pdf>
+     figure 14.  */
+  if (setresuid (-1, uid, saved_uid) < 0)
+    return -1;
+# else /* Mac OS X, NetBSD, AIX, IRIX, Solaris >= 2.5, OSF/1, Cygwin */
+  if (setreuid (-1, uid) < 0)
+    return -1;
+# endif
+
+  /* Verify that the privileges have really been dropped.
+     This verification is here for security reasons.  Doesn't matter if it
+     takes a couple of system calls.
+     When the verification fails, it indicates that we need to use different
+     API in the code above. Therefore 'abort ()', not 'return -1'.  */
+# if HAVE_GETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */
+  {
+    uid_t real;
+    uid_t effective;
+    uid_t saved;
+    if (getresuid (&real, &effective, &saved) < 0
+        || real != uid
+        || effective != uid
+        || saved != saved_uid)
+      abort ();
+  }
+# else
+#  if HAVE_GETEUID
+  if (geteuid () != uid)
+    abort ();
+#  endif
+  if (getuid () != uid)
+    abort ();
+# endif
+# if HAVE_GETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */
+  {
+    uid_t real;
+    uid_t effective;
+    uid_t saved;
+    if (getresgid (&real, &effective, &saved) < 0
+        || real != gid
+        || effective != gid
+        || saved != saved_gid)
+      abort ();
+  }
+# else
+#  if HAVE_GETEGID
+  if (getegid () != gid)
+    abort ();
+#  endif
+  if (getgid () != gid)
+    abort ();
+# endif
+
+  return 0;
+#else
+  errno = ENOSYS;
+  return -1;
+#endif
+}
+
+int
+idpriv_temp_restore (void)
+{
+#if HAVE_GETEUID && HAVE_GETEGID && (HAVE_SETRESUID || HAVE_SETREUID) && (HAVE_SETRESGID || HAVE_SETREGID)
+  int uid = getuid ();
+  int gid = getgid ();
+
+  if (saved_uid == -1 || saved_gid == -1)
+    /* Caller error: idpriv_temp_drop was never invoked.  */
+    abort ();
+
+  /* Acquire the gid privilege last, because in some cases the gid privilege
+     cannot be acquired before the uid privilege has been acquired.  */
+
+  /* This is for executables that have the setuid bit set.  */
+# if HAVE_SETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */
+  /* See <http://www.usenix.org/events/sec02/full_papers/chen/chen.pdf>
+     figure 14.  */
+  if (setresuid (-1, saved_uid, -1) < 0)
+    return -1;
+# else /* Mac OS X, NetBSD, AIX, IRIX, Solaris >= 2.5, OSF/1, Cygwin */
+  if (setreuid (-1, saved_uid) < 0)
+    return -1;
+# endif
+
+  /* This is for executables that have the setgid bit set.  */
+# if HAVE_SETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */
+  if (setresgid (-1, saved_gid, -1) < 0)
+    return -1;
+# else /* Mac OS X, NetBSD, AIX, IRIX, Solaris >= 2.5, OSF/1, Cygwin */
+  if (setregid (-1, saved_gid) < 0)
+    return -1;
+# endif
+
+  /* Verify that the privileges have really been acquired.
+     This verification is here for security reasons.  Doesn't matter if it
+     takes a couple of system calls.
+     When the verification fails, it indicates that we need to use different
+     API in the code above. Therefore 'abort ()', not 'return -1'.  */
+# if HAVE_GETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */
+  {
+    uid_t real;
+    uid_t effective;
+    uid_t saved;
+    if (getresuid (&real, &effective, &saved) < 0
+        || real != uid
+        || effective != saved_uid
+        || saved != saved_uid)
+      abort ();
+  }
+# else
+#  if HAVE_GETEUID
+  if (geteuid () != saved_uid)
+    abort ();
+#  endif
+  if (getuid () != uid)
+    abort ();
+# endif
+# if HAVE_GETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */
+  {
+    uid_t real;
+    uid_t effective;
+    uid_t saved;
+    if (getresgid (&real, &effective, &saved) < 0
+        || real != gid
+        || effective != saved_gid
+        || saved != saved_gid)
+      abort ();
+  }
+# else
+#  if HAVE_GETEGID
+  if (getegid () != saved_gid)
+    abort ();
+#  endif
+  if (getgid () != gid)
+    abort ();
+# endif
+
+  return 0;
+#else
+  errno = ENOSYS;
+  return -1;
+#endif
+}

+ 116 - 0
gl/idpriv.h

@@ -0,0 +1,116 @@
+/* Dropping uid/gid privileges of the current process.
+   Copyright (C) 2009-2013 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _IDPRIV_H
+#define _IDPRIV_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This module allows programs which are installed with setuid or setgid bit
+   (and which therefore initially run with an effective user id or group id
+   different from the one of the current user) to drop their uid or gid
+   privilege, either permanently or temporarily.
+
+   It is absolutely necessary to minimize the amount of code that is running
+   with escalated privileges (e.g. with effective uid = root). The reason is
+   that any bug or exploit in a part of a program that is running with
+   escalated privileges is a security vulnerability that - upon discovery -
+   puts the users in danger and requires immediate fixing. Then consider that
+   there's a bug every 10 or 20 lines of code on average...
+
+   For programs that temporarily drop privileges but have the ability to
+   restore them later, there are additionally the dangers that
+     - Any bug in the non-privileged part of the program may be used to
+       create invalid data structures that will trigger security
+       vulnerabilities in the privileged part of the program.
+     - Code execution exploits in the non-privileged part of the program may
+       be used to invoke the function that restores high privileges and then
+       execute additional arbitrary code.
+
+   1) The usual, and reasonably safe, way to minimize the amount of code
+      running with privileges is to create a separate executable, with setuid
+      or setgid bit, that contains only code for the tasks that require
+      privileges (and,of course, strict checking of the arguments, so that the
+      program cannot be abused). The main program is installed without setuid
+      or setgid bit.
+
+   2) A less safe way is to do some privileged tasks at the beginning of the
+      program's run, and drop privileges permanently as soon as possible.
+
+      Note: There may still be security issues if the privileged task puts
+      sensitive data into the process memory or opens communication channels
+      to restricted facilities.
+
+   3) The most unsafe way is to drop privileges temporarily for most of the
+      main program but to re-enable them for the duration of privileged tasks.
+
+      As explained above, this approach has uncontrollable dangers for
+      security.
+
+      This approach is normally not usable in multithreaded programs, because
+      you cannot know what kind of system calls the other threads could be
+      doing during the time the privileges are enabled.
+
+   With approach 1, you don't need gnulib modules.
+   With approach 2, you need the gnulib module 'idpriv-drop'.
+   With approach 3, you need the gnulib module 'idpriv-droptemp'. But really,
+   you should better stay away from this approach.
+ */
+
+/* For more in-depth discussion of these topics, see the papers/articles
+   * Hao Chen, David Wagner, Drew Dean: Setuid Demystified
+     <http://www.usenix.org/events/sec02/full_papers/chen/chen.pdf>
+   * Dan Tsafrir, Dilma da Silva, David Wagner: The Murky Issue of Changing
+     Process Identity: Revising "Setuid Demystified"
+     <http://www.eecs.berkeley.edu/~daw/papers/setuid-login08b.pdf>
+     <http://code.google.com/p/change-process-identity/>
+   * Dhruv Mohindra: Observe correct revocation order while relinquishing
+     privileges
+     <https://www.securecoding.cert.org/confluence/display/seccode/POS36-C.+Observe+correct+revocation+order+while+relinquishing+privileges>
+ */
+
+
+/* For approach 2.  */
+
+/* Drop the uid and gid privileges of the current process.
+   Return 0 if successful, or -1 with errno set upon failure. The recommended
+   handling of failure is to terminate the process.  */
+extern int idpriv_drop (void);
+
+
+/* For approach 3.  */
+
+/* Drop the uid and gid privileges of the current process in a way that allows
+   them to be restored later.
+   Return 0 if successful, or -1 with errno set upon failure. The recommended
+   handling of failure is to terminate the process.  */
+extern int idpriv_temp_drop (void);
+
+/* Restore the uid and gid privileges of the current process.
+   Return 0 if successful, or -1 with errno set upon failure. The recommended
+   handling of failure is to not perform the actions that require the escalated
+   privileges.  */
+extern int idpriv_temp_restore (void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _IDPRIV_H */

+ 2 - 1
gl/m4/gnulib-cache.m4

@@ -27,7 +27,7 @@
 
 
 # Specification in the form of a command-line invocation:
-#   gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files base64 crypto/sha1 dirname environ floorf fsusage getaddrinfo gethostname getloadavg getopt-gnu gettext mountlist regex setenv strcase strsep timegm unsetenv vasprintf vsnprintf
+#   gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files base64 crypto/sha1 dirname environ floorf fsusage getaddrinfo gethostname getloadavg getopt-gnu gettext idpriv-droptemp mountlist regex setenv strcase strsep timegm unsetenv vasprintf vsnprintf
 
 # Specification in the form of a few gnulib-tool.m4 macro invocations:
 gl_LOCAL_DIR([])
@@ -43,6 +43,7 @@ gl_MODULES([
   getloadavg
   getopt-gnu
   gettext
+  idpriv-droptemp
   mountlist
   regex
   setenv

+ 7 - 2
gl/m4/gnulib-comp.m4

@@ -28,7 +28,7 @@
 # other built files.
 
 
-# This macro should be invoked from ./configure.in, in the section
+# This macro should be invoked from ./configure.ac, in the section
 # "Checks for programs", right after AC_PROG_CC, and certainly before
 # any checks for libraries, header files, types and library functions.
 AC_DEFUN([gl_EARLY],
@@ -70,6 +70,7 @@ AC_DEFUN([gl_EARLY],
   # Code from module gettext-h:
   # Code from module havelib:
   # Code from module hostent:
+  # Code from module idpriv-droptemp:
   # Code from module include_next:
   # Code from module inet_ntop:
   # Code from module intprops:
@@ -153,7 +154,7 @@ AC_DEFUN([gl_EARLY],
   # Code from module xstrndup:
 ])
 
-# This macro should be invoked from ./configure.in, in the section
+# This macro should be invoked from ./configure.ac, in the section
 # "Check for header files, types and library functions".
 AC_DEFUN([gl_INIT],
 [
@@ -258,6 +259,7 @@ AC_DEFUN([gl_INIT],
   AC_SUBST([LIBINTL])
   AC_SUBST([LTLIBINTL])
   gl_HOSTENT
+  gl_IDPRIV
   gl_FUNC_INET_NTOP
   if test $HAVE_INET_NTOP = 0 || test $REPLACE_INET_NTOP = 1; then
     AC_LIBOBJ([inet_ntop])
@@ -658,6 +660,8 @@ AC_DEFUN([gl_FILE_LIST], [
   lib/glthread/lock.c
   lib/glthread/lock.h
   lib/glthread/threadlib.c
+  lib/idpriv-droptemp.c
+  lib/idpriv.h
   lib/inet_ntop.c
   lib/intprops.h
   lib/itold.c
@@ -790,6 +794,7 @@ AC_DEFUN([gl_FILE_LIST], [
   m4/gnulib-common.m4
   m4/hostent.m4
   m4/iconv.m4
+  m4/idpriv.m4
   m4/include_next.m4
   m4/inet_ntop.m4
   m4/intdiv0.m4

+ 14 - 0
gl/m4/idpriv.m4

@@ -0,0 +1,14 @@
+# idpriv.m4 serial 1
+dnl Copyright (C) 2009-2013 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_IDPRIV],
+[
+  dnl Persuade glibc <unistd.h> to declare {get,set}res{uid,gid}.
+  AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+
+  AC_CHECK_FUNCS_ONCE([getuid geteuid getresuid getgid getegid getresgid])
+  AC_CHECK_FUNCS_ONCE([setresuid setreuid seteuid setresgid setregid setegid])
+])

+ 261 - 231
lib/parse_ini.c

@@ -22,16 +22,15 @@
 *****************************************************************************/
 
 #include "common.h"
+#include "idpriv.h"
 #include "utils_base.h"
 #include "parse_ini.h"
-#include <ctype.h>
 
+#include <ctype.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
-/* TODO: die like N::P if config file is not found */
-
 /* np_ini_info contains the result of parsing a "locator" in the format
  * [stanza_name][@config_filename] (check_foo@/etc/foo.ini, for example)
  */
@@ -40,254 +39,314 @@ typedef struct {
 	char *stanza;
 } np_ini_info;
 
+static char *default_ini_file_names[] = {
+	"monitoring-plugins.ini",
+	"plugins.ini",
+	"nagios-plugins.ini",
+	NULL
+};
+
+static char *default_ini_path_names[] = {
+	"/usr/local/etc/monitoring-plugins/monitoring-plugins.ini",
+	"/usr/local/etc/monitoring-plugins.ini",
+	"/etc/monitoring-plugins/monitoring-plugins.ini",
+	"/etc/monitoring-plugins.ini",
+	/* deprecated path names (for backward compatibility): */
+	"/etc/nagios/plugins.ini",
+	"/usr/local/nagios/etc/plugins.ini",
+	"/usr/local/etc/nagios/plugins.ini",
+	"/etc/opt/nagios/plugins.ini",
+	"/etc/nagios-plugins.ini",
+	"/usr/local/etc/nagios-plugins.ini",
+	"/etc/opt/nagios-plugins.ini",
+	NULL
+};
+
 /* eat all characters from a FILE pointer until n is encountered */
 #define GOBBLE_TO(f, c, n) do { (c)=fgetc((f)); } while((c)!=EOF && (c)!=(n))
 
 /* internal function that returns the constructed defaults options */
 static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts);
+
 /* internal function that converts a single line into options format */
 static int add_option(FILE *f, np_arg_list **optlst);
-/* internal function to find default file */
-static char* default_file(void);
-/* internal function to test files access */
-static int test_file(const char* env, int len, const char* file, char* temp_file);
 
-/* parse_locator decomposes a string of the form
+/* internal functions to find default file */
+static char *default_file(void);
+static char *default_file_in_path(void);
+
+/*
+ * Parse_locator decomposes a string of the form
  * 	[stanza][@filename]
- * into its seperate parts
+ * into its seperate parts.
  */
-static void parse_locator(const char *locator, const char *def_stanza, np_ini_info *i){
-	size_t locator_len=0, stanza_len=0;
+static void
+parse_locator(const char *locator, const char *def_stanza, np_ini_info *i)
+{
+	size_t locator_len = 0, stanza_len = 0;
 
 	/* if locator is NULL we'll use default values */
-	if(locator){
-		locator_len=strlen(locator);
-		stanza_len=strcspn(locator, "@");
+	if (locator != NULL) {
+		locator_len = strlen(locator);
+		stanza_len = strcspn(locator, "@");
 	}
 	/* if a non-default stanza is provided */
-	if(stanza_len>0){
-		i->stanza=(char*)malloc(sizeof(char)*(stanza_len+1));
+	if (stanza_len > 0) {
+		i->stanza = malloc(sizeof(char) * (stanza_len + 1));
 		strncpy(i->stanza, locator, stanza_len);
-		i->stanza[stanza_len]='\0';
-	} else { /* otherwise we use the default stanza */
-		i->stanza=strdup(def_stanza);
-	}
-	/* if there is no @file part */
-	if(stanza_len==locator_len){
-		i->file=default_file();
-		if(strcmp(i->file, "") == 0){
-			die(STATE_UNKNOWN, _("Cannot find '%s' or '%s' in any standard location.\n"), NP_DEFAULT_INI_FILENAME1, NP_DEFAULT_INI_FILENAME2);
-		}
-	} else {
-		i->file=strdup(&(locator[stanza_len+1]));
-	}
+		i->stanza[stanza_len] = '\0';
+	} else	/* otherwise we use the default stanza */
+		i->stanza = strdup(def_stanza);
 
-	if(i->file==NULL || i->stanza==NULL){
+	if (i->stanza == NULL)
 		die(STATE_UNKNOWN, _("malloc() failed!\n"));
-	}
+
+	/* check whether there's an @file part */
+	i->file = stanza_len == locator_len
+	    ? default_file()
+	    : strdup(&(locator[stanza_len + 1]));
+	if (i->file == NULL || i->file[0] == '\0')
+		die(STATE_UNKNOWN,
+		    _("Cannot find config file in any standard location.\n"));
 }
 
-/* this is the externally visible function used by extra_opts */
-np_arg_list* np_get_defaults(const char *locator, const char *default_section){
-	FILE *inifile=NULL;
-	np_arg_list *defaults=NULL;
+/*
+ * This is the externally visible function used by extra_opts.
+ */
+np_arg_list *
+np_get_defaults(const char *locator, const char *default_section)
+{
+	FILE *inifile = NULL;
+	np_arg_list *defaults = NULL;
 	np_ini_info i;
+	int is_suid_plugin = mp_suid();
 
-	parse_locator(locator, default_section, &i);
-	/* if a file was specified or if we're using the default file */
-	if(i.file != NULL && strlen(i.file) > 0){
-		if(strcmp(i.file, "-")==0){
-			inifile=stdin;
-		} else {
-			inifile=fopen(i.file, "r");
-		}
-		if(inifile==NULL) die(STATE_UNKNOWN, "%s\n", _("Can't read config file"));
-		if(read_defaults(inifile, i.stanza, &defaults)==FALSE)
-			die(STATE_UNKNOWN, _("Invalid section '%s' in config file '%s'\n"), i.stanza, i.file);
+	if (is_suid_plugin && idpriv_temp_drop() == -1)
+		die(STATE_UNKNOWN, _("Cannot drop privileges: %s\n"),
+		    strerror(errno));
 
-		free(i.file);
-		if(inifile!=stdin) fclose(inifile);
-	}
+	parse_locator(locator, default_section, &i);
+	inifile = strcmp(i.file, "-") == 0 ? stdin : fopen(i.file, "r");
+
+	if (inifile == NULL)
+		die(STATE_UNKNOWN, _("Can't read config file: %s\n"),
+		    strerror(errno));
+	if (read_defaults(inifile, i.stanza, &defaults) == FALSE)
+		die(STATE_UNKNOWN,
+		    _("Invalid section '%s' in config file '%s'\n"), i.stanza,
+		    i.file);
+
+	free(i.file);
+	if (inifile != stdin)
+		fclose(inifile);
 	free(i.stanza);
+	if (is_suid_plugin && idpriv_temp_restore() == -1)
+		die(STATE_UNKNOWN, _("Cannot restore privileges: %s\n"),
+		    strerror(errno));
+
 	return defaults;
 }
 
-/* read_defaults is where the meat of the parsing takes place.
+/*
+ * The read_defaults() function is where the meat of the parsing takes place.
  *
- * note that this may be called by a setuid binary, so we need to
+ * Note that this may be called by a setuid binary, so we need to
  * be extra careful about user-supplied input (i.e. avoiding possible
- * format string vulnerabilities, etc)
+ * format string vulnerabilities, etc).
  */
-static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts){
-	int c, status=FALSE;
+static int
+read_defaults(FILE *f, const char *stanza, np_arg_list **opts)
+{
+	int c, status = FALSE;
 	size_t i, stanza_len;
-	enum { NOSTANZA, WRONGSTANZA, RIGHTSTANZA } stanzastate=NOSTANZA;
+	enum { NOSTANZA, WRONGSTANZA, RIGHTSTANZA } stanzastate = NOSTANZA;
 
-	stanza_len=strlen(stanza);
+	stanza_len = strlen(stanza);
 
-	/* our little stanza-parsing state machine.  */
-	while((c=fgetc(f))!=EOF){
+	/* our little stanza-parsing state machine */
+	while ((c = fgetc(f)) != EOF) {
 		/* gobble up leading whitespace */
-		if(isspace(c)) continue;
-		switch(c){
+		if (isspace(c))
+			continue;
+		switch (c) {
 			/* globble up coment lines */
-			case ';':
-			case '#':
-				GOBBLE_TO(f, c, '\n');
-				break;
-			/* start of a stanza.  check to see if it matches */
-			case '[':
-				stanzastate=WRONGSTANZA;
-				for(i=0; i<stanza_len; i++){
-					c=fgetc(f);
-					/* Strip leading whitespace */
-					if(i==0) for(c; isspace(c); c=fgetc(f));
-					/* nope, read to the end of the line */
-					if(c!=stanza[i]) {
-						GOBBLE_TO(f, c, '\n');
-						break;
-					}
-				}
-				/* if it matched up to here and the next char is ']'... */
-				if(i==stanza_len){
-					c=fgetc(f);
-					/* Strip trailing whitespace */
-					for(c; isspace(c); c=fgetc(f));
-					if(c==']') stanzastate=RIGHTSTANZA;
+		case ';':
+		case '#':
+			GOBBLE_TO(f, c, '\n');
+			break;
+			/* start of a stanza, check to see if it matches */
+		case '[':
+			stanzastate = WRONGSTANZA;
+			for (i = 0; i < stanza_len; i++) {
+				c = fgetc(f);
+				/* strip leading whitespace */
+				if (i == 0)
+					for (; isspace(c); c = fgetc(f))
+						continue;
+				/* nope, read to the end of the line */
+				if (c != stanza[i]) {
+					GOBBLE_TO(f, c, '\n');
+					break;
 				}
-				break;
+			}
+			/* if it matched up to here and the next char is ']'... */
+			if (i == stanza_len) {
+				c = fgetc(f);
+				/* strip trailing whitespace */
+				for (; isspace(c); c = fgetc(f))
+					continue;
+				if (c == ']')
+					stanzastate = RIGHTSTANZA;
+			}
+			break;
 			/* otherwise, we're in the body of a stanza or a parse error */
-			default:
-				switch(stanzastate){
-					/* we never found the start of the first stanza, so
-					 * we're dealing with a config error
-					 */
-					case NOSTANZA:
-						die(STATE_UNKNOWN, "%s\n", _("Config file error"));
-						break;
-					/* we're in a stanza, but for a different plugin */
-					case WRONGSTANZA:
-						GOBBLE_TO(f, c, '\n');
-						break;
-					/* okay, this is where we start taking the config */
-					case RIGHTSTANZA:
-						ungetc(c, f);
-						if(add_option(f, opts)){
-							die(STATE_UNKNOWN, "%s\n", _("Config file error"));
-						}
-						status=TRUE;
-						break;
+		default:
+			switch (stanzastate) {
+				/* we never found the start of the first stanza, so
+				 * we're dealing with a config error
+				 */
+			case NOSTANZA:
+				die(STATE_UNKNOWN, "%s\n",
+				    _("Config file error"));
+				/* we're in a stanza, but for a different plugin */
+			case WRONGSTANZA:
+				GOBBLE_TO(f, c, '\n');
+				break;
+				/* okay, this is where we start taking the config */
+			case RIGHTSTANZA:
+				ungetc(c, f);
+				if (add_option(f, opts)) {
+					die(STATE_UNKNOWN, "%s\n",
+					    _("Config file error"));
 				}
+				status = TRUE;
 				break;
+			}
+			break;
 		}
 	}
 	return status;
 }
 
 /*
- * read one line of input in the format
+ * Read one line of input in the format
  * 	^option[[:space:]]*(=[[:space:]]*value)?
- * and creates it as a cmdline argument
+ * and create it as a cmdline argument
  * 	--option[=value]
  * appending it to the linked list optbuf.
  */
-static int add_option(FILE *f, np_arg_list **optlst){
-	np_arg_list *opttmp=*optlst, *optnew;
-	char *linebuf=NULL, *lineend=NULL, *optptr=NULL, *optend=NULL;
-	char *eqptr=NULL, *valptr=NULL, *spaceptr=NULL, *valend=NULL;
-	short done_reading=0, equals=0, value=0;
-	size_t cfg_len=0, read_sz=8, linebuf_sz=0, read_pos=0;
-	size_t opt_len=0, val_len=0;
+static int
+add_option(FILE *f, np_arg_list **optlst)
+{
+	np_arg_list *opttmp = *optlst, *optnew;
+	char *linebuf = NULL, *lineend = NULL, *optptr = NULL, *optend = NULL;
+	char *eqptr = NULL, *valptr = NULL, *valend = NULL;
+	short done_reading = 0, equals = 0, value = 0;
+	size_t cfg_len = 0, read_sz = 8, linebuf_sz = 0, read_pos = 0;
+	size_t opt_len = 0, val_len = 0;
 
 	/* read one line from the file */
-	while(!done_reading){
+	while (!done_reading) {
 		/* grow if necessary */
-		if(linebuf==NULL || read_pos+read_sz >= linebuf_sz){
-			linebuf_sz=(linebuf_sz>0)?linebuf_sz<<1:read_sz;
-			linebuf=realloc(linebuf, linebuf_sz);
-			if(linebuf==NULL) die(STATE_UNKNOWN, _("malloc() failed!\n"));
+		if (linebuf == NULL || read_pos + read_sz >= linebuf_sz) {
+			linebuf_sz = linebuf_sz > 0 ? linebuf_sz << 1 : read_sz;
+			linebuf = realloc(linebuf, linebuf_sz);
+			if (linebuf == NULL)
+				die(STATE_UNKNOWN, _("malloc() failed!\n"));
 		}
-		if(fgets(&linebuf[read_pos], read_sz, f)==NULL) done_reading=1;
+		if (fgets(&linebuf[read_pos], (int)read_sz, f) == NULL)
+			done_reading = 1;
 		else {
-			read_pos=strlen(linebuf);
-			if(linebuf[read_pos-1]=='\n') {
-				linebuf[--read_pos]='\0';
-				done_reading=1;
+			read_pos = strlen(linebuf);
+			if (linebuf[read_pos - 1] == '\n') {
+				linebuf[--read_pos] = '\0';
+				done_reading = 1;
 			}
 		}
 	}
-	lineend=&linebuf[read_pos];
-	/* all that to read one line.  isn't C fun? :) now comes the parsing :/ */
+	lineend = &linebuf[read_pos];
+	/* all that to read one line, isn't C fun? :) now comes the parsing :/ */
 
 	/* skip leading whitespace */
-	for(optptr=linebuf; optptr<lineend && isspace(*optptr); optptr++);
+	for (optptr = linebuf; optptr < lineend && isspace(*optptr); optptr++)
+		continue;
 	/* continue to '=' or EOL, watching for spaces that might precede it */
-	for(eqptr=optptr; eqptr<lineend && *eqptr!='='; eqptr++){
-		if(isspace(*eqptr) && optend==NULL) optend=eqptr;
-		else optend=NULL;
+	for (eqptr = optptr; eqptr < lineend && *eqptr != '='; eqptr++) {
+		if (isspace(*eqptr) && optend == NULL)
+			optend = eqptr;
+		else
+			optend = NULL;
 	}
-	if(optend==NULL) optend=eqptr;
+	if (optend == NULL)
+		optend = eqptr;
 	--optend;
 	/* ^[[:space:]]*=foo is a syntax error */
-	if(optptr==eqptr) die(STATE_UNKNOWN, "%s\n", _("Config file error"));
+	if (optptr == eqptr)
+		die(STATE_UNKNOWN, "%s\n", _("Config file error"));
 	/* continue from '=' to start of value or EOL */
-	for(valptr=eqptr+1; valptr<lineend && isspace(*valptr); valptr++);
+	for (valptr = eqptr + 1; valptr < lineend && isspace(*valptr);
+	    valptr++)
+		continue;
 	/* continue to the end of value */
-	for(valend=valptr; valend<lineend; valend++);
+	for (valend = valptr; valend < lineend; valend++)
+		continue;
 	--valend;
-	/* Finally trim off trailing spaces */
-	for(valend; isspace(*valend); valend--);
+	/* finally trim off trailing spaces */
+	for (; isspace(*valend); valend--)
+		continue;
 	/* calculate the length of "--foo" */
-	opt_len=1+optend-optptr;
+	opt_len = (size_t)(1 + optend - optptr);
 	/* 1-character params needs only one dash */
-	if(opt_len==1)
-		cfg_len=1+(opt_len);
+	if (opt_len == 1)
+		cfg_len = 1 + (opt_len);
 	else
-		cfg_len=2+(opt_len);
+		cfg_len = 2 + (opt_len);
 	/* if valptr<lineend then we have to also allocate space for "=bar" */
-	if(valptr<lineend) {
-		equals=value=1;
-		val_len=1+valend-valptr;
-		cfg_len+=1+val_len;
+	if (valptr < lineend) {
+		equals = value = 1;
+		val_len = (size_t)(1 + valend - valptr);
+		cfg_len += 1 + val_len;
 	}
 	/* if valptr==valend then we have "=" but no "bar" */
-	else if(valptr==lineend) {
-		equals=1;
-		cfg_len+=1;
+	else if (valptr == lineend) {
+		equals = 1;
+		cfg_len += 1;
 	}
-	/* A line with no equal sign isn't valid */
-	if(equals==0) die(STATE_UNKNOWN, "%s\n", _("Config file error"));
+	/* a line with no equal sign isn't valid */
+	if (equals == 0)
+		die(STATE_UNKNOWN, "%s\n", _("Config file error"));
 
 	/* okay, now we have all the info we need, so we create a new np_arg_list
 	 * element and set the argument...
 	 */
-	optnew=(np_arg_list *)malloc(sizeof(np_arg_list));
-	optnew->next=NULL;
+	optnew = malloc(sizeof(np_arg_list));
+	optnew->next = NULL;
 
-	read_pos=0;
-	optnew->arg=(char *)malloc(cfg_len+1);
+	read_pos = 0;
+	optnew->arg = malloc(cfg_len + 1);
 	/* 1-character params needs only one dash */
-	if(opt_len==1) {
+	if (opt_len == 1) {
 		strncpy(&optnew->arg[read_pos], "-", 1);
-		read_pos+=1;
+		read_pos += 1;
 	} else {
 		strncpy(&optnew->arg[read_pos], "--", 2);
-		read_pos+=2;
+		read_pos += 2;
 	}
-	strncpy(&optnew->arg[read_pos], optptr, opt_len); read_pos+=opt_len;
-	if(value) {
-		optnew->arg[read_pos++]='=';
-		strncpy(&optnew->arg[read_pos], valptr, val_len); read_pos+=val_len;
+	strncpy(&optnew->arg[read_pos], optptr, opt_len);
+	read_pos += opt_len;
+	if (value) {
+		optnew->arg[read_pos++] = '=';
+		strncpy(&optnew->arg[read_pos], valptr, val_len);
+		read_pos += val_len;
 	}
-	optnew->arg[read_pos]='\0';
+	optnew->arg[read_pos] = '\0';
 
 	/* ...and put that to the end of the list */
-	if(*optlst==NULL) {
-		*optlst=optnew;
-	}	else {
-		while(opttmp->next!=NULL) {
-			opttmp=opttmp->next;
-		}
+	if (*optlst == NULL)
+		*optlst = optnew;
+	else {
+		while (opttmp->next != NULL)
+			opttmp = opttmp->next;
 		opttmp->next = optnew;
 	}
 
@@ -295,71 +354,42 @@ static int add_option(FILE *f, np_arg_list **optlst){
 	return 0;
 }
 
-static char* default_file(void){
-	struct stat sb;
-	char *np_env=NULL, *default_file=NULL;
-	char temp_file[MAX_INPUT_BUFFER];
-	size_t len;
-
-	if((np_env=getenv("NAGIOS_CONFIG_PATH"))!=NULL) {
-		/* skip any starting colon... */
-		while(*np_env==':') np_env++;
-		/* Look for NP_DEFAULT_INI_FILENAME1 and NP_DEFAULT_INI_FILENAME2 in
-		 * every PATHs defined (colon-separated).
-		 */
-		while((len=strcspn(np_env,":"))>0){
-			/* Test NP_DEFAULT_INI_FILENAME[1-2] in current np_env token */
-			if(test_file(np_env,len,NP_DEFAULT_INI_FILENAME1,temp_file)==1 ||
-			   test_file(np_env,len,NP_DEFAULT_INI_FILENAME2,temp_file)==1){
-				default_file=strdup(temp_file);
-				break;
-			}
-
-			/* Move on to the next token */
-			np_env+=len;
-			while(*np_env==':') np_env++;
-		} /* while(...) */
-	} /* if(getenv("NAGIOS_CONFIG_PATH")) */
-
-	/* Look for NP_DEFAULT_INI_FILENAME1 in NP_DEFAULT_INI_NAGIOS_PATH[1-4] */
-	if(!default_file){
-		if(test_file(NP_DEFAULT_INI_NAGIOS_PATH1,strlen(NP_DEFAULT_INI_NAGIOS_PATH1),NP_DEFAULT_INI_FILENAME1,temp_file)==1 ||
-		   test_file(NP_DEFAULT_INI_NAGIOS_PATH2,strlen(NP_DEFAULT_INI_NAGIOS_PATH2),NP_DEFAULT_INI_FILENAME1,temp_file)==1 ||
-		   test_file(NP_DEFAULT_INI_NAGIOS_PATH3,strlen(NP_DEFAULT_INI_NAGIOS_PATH3),NP_DEFAULT_INI_FILENAME1,temp_file)==1 ||
-		   test_file(NP_DEFAULT_INI_NAGIOS_PATH4,strlen(NP_DEFAULT_INI_NAGIOS_PATH4),NP_DEFAULT_INI_FILENAME1,temp_file)==1)
-			default_file=strdup(temp_file);
-	}
-
-	/* Look for NP_DEFAULT_INI_FILENAME2 in NP_DEFAULT_INI_PATH[1-3] */
-	if(!default_file){
-		if(test_file(NP_DEFAULT_INI_PATH1,strlen(NP_DEFAULT_INI_PATH1),NP_DEFAULT_INI_FILENAME2,temp_file)==1 ||
-		   test_file(NP_DEFAULT_INI_PATH2,strlen(NP_DEFAULT_INI_PATH2),NP_DEFAULT_INI_FILENAME2,temp_file)==1 ||
-		   test_file(NP_DEFAULT_INI_PATH3,strlen(NP_DEFAULT_INI_PATH3),NP_DEFAULT_INI_FILENAME2,temp_file)==1)
-			default_file=strdup(temp_file);
-	}
-
-	/* Return default_file or empty string (should return NULL if we want plugins
-	 * to die there)...
-	 */
-	if(default_file)
-		return default_file;
-	return "";
+static char *
+default_file(void)
+{
+	char **p, *ini_file;
+
+	if ((ini_file = getenv("MP_CONFIG_FILE")) != NULL ||
+	    (ini_file = default_file_in_path()) != NULL)
+		return ini_file;
+	for (p = default_ini_path_names; *p != NULL; p++)
+		if (access(*p, F_OK) == 0)
+			return *p;
+	return NULL;
 }
 
-/* put together len bytes from env and the filename and test for its
- * existence. Returns 1 if found, 0 if not and -1 if test wasn't performed.
- */
-static int test_file(const char* env, int len, const char* file, char* temp_file){
-
-	/* test if len + filelen + '/' + '\0' fits in temp_file */
-	if((len+strlen(file)+2)>MAX_INPUT_BUFFER)	return -1;
-
-	strncpy(temp_file,env,len);
-	temp_file[len]='\0';
-	strncat(temp_file,"/",len+1);
-	strncat(temp_file,file,len+strlen(file)+1);
-
-	if(access(temp_file, F_OK) == 0) return 1;
-	return 0;
+static char *
+default_file_in_path(void)
+{
+	char *config_path, **file;
+	char *dir, *ini_file, *tokens;
+
+	if ((config_path = getenv("NAGIOS_CONFIG_PATH")) == NULL)
+		return NULL;
+	/* shall we spit out a warning that NAGIOS_CONFIG_PATH is deprecated? */
+
+	if ((tokens = strdup(config_path)) == NULL)
+		die(STATE_UNKNOWN, "%s\n", _("Insufficient Memory"));
+	for (dir = strtok(tokens, ":"); dir != NULL; dir = strtok(NULL, ":")) {
+		for (file = default_ini_file_names; *file != NULL; file++) {
+			if ((asprintf(&ini_file, "%s/%s", dir, *file)) < 0)
+				die(STATE_UNKNOWN, "%s\n", _("Insufficient Memory"));
+			if (access(ini_file, F_OK) == 0) {
+				free(tokens);
+				return ini_file;
+			}
+		}
+	}
+	free(tokens);
+	return NULL;
 }
-

+ 1 - 41
lib/parse_ini.h

@@ -13,50 +13,10 @@ typedef struct np_arg_el {
 	struct np_arg_el *next;
 } np_arg_list;
 
-/* FIXME: This is in plugins/common.c. Should be eventually moved to lib/
- * (although for this particular one a configure settings should be ideal)
- */
-#ifndef MAX_INPUT_BUFFER
-# define MAX_INPUT_BUFFER 8192
-#endif /* MAX_INPUT_BUFFER */
-
-/* Filenames (see below) */
-#ifndef NP_DEFAULT_INI_FILENAME1
-# define NP_DEFAULT_INI_FILENAME1 "plugins.ini"
-#endif /* NP_DEFAULT_INI_FILENAME1 */
-#ifndef NP_DEFAULT_INI_FILENAME2
-# define NP_DEFAULT_INI_FILENAME2 "nagios-plugins.ini"
-#endif /* NP_DEFAULT_INI_FILENAME2 */
-
-/* Config paths ending in nagios (search for NP_DEFAULT_INI_FILENAME1) */
-#ifndef NP_DEFAULT_INI_NAGIOS_PATH1
-# define NP_DEFAULT_INI_NAGIOS_PATH1 "/etc/nagios"
-#endif /* NP_DEFAULT_INI_NAGIOS_PATH1 */
-#ifndef NP_DEFAULT_INI_NAGIOS_PATH2
-# define NP_DEFAULT_INI_NAGIOS_PATH2 "/usr/local/nagios/etc"
-#endif /* NP_DEFAULT_INI_NAGIOS_PATH2 */
-#ifndef NP_DEFAULT_INI_NAGIOS_PATH3
-# define NP_DEFAULT_INI_NAGIOS_PATH3 "/usr/local/etc/nagios"
-#endif /* NP_DEFAULT_INI_NAGIOS_PATH3 */
-#ifndef NP_DEFAULT_INI_NAGIOS_PATH4
-# define NP_DEFAULT_INI_NAGIOS_PATH4 "/etc/opt/nagios"
-#endif /* NP_DEFAULT_INI_NAGIOS_PATH4 */
-
-/* Config paths not ending in nagios (search for NP_DEFAULT_INI_FILENAME2) */
-#ifndef NP_DEFAULT_INI_PATH1
-# define NP_DEFAULT_INI_PATH1 "/etc"
-#endif /* NP_DEFAULT_INI_PATH1 */
-#ifndef NP_DEFAULT_INI_PATH2
-# define NP_DEFAULT_INI_PATH2 "/usr/local/etc"
-#endif /* NP_DEFAULT_INI_PATH2 */
-#ifndef NP_DEFAULT_INI_PATH3
-# define NP_DEFAULT_INI_PATH3 "/etc/opt"
-#endif /* NP_DEFAULT_INI_PATH3 */
-
 /* np_load_defaults: load the default configuration (if present) for
  * a plugin from the ini file
  */
-np_arg_list* np_get_defaults(const char *locator, const char *default_section);
+np_arg_list *np_get_defaults(const char *locator, const char *default_section);
 
 #endif /* _PARSE_INI_H_ */
 

+ 6 - 2
lib/tests/test_utils.c

@@ -21,6 +21,7 @@
 
 #include "tap.h"
 
+#include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
@@ -29,6 +30,7 @@
 int
 main (int argc, char **argv)
 {
+	char state_path[1024];
 	range	*range;
 	double	temp;
 	thresholds *thresholds = NULL;
@@ -345,9 +347,10 @@ main (int argc, char **argv)
 
 	np_enable_state("allowedchars_in_keyname", 77);
 	temp_state_key = this_monitoring_plugin->state;
+	sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/allowedchars_in_keyname", (unsigned long)geteuid());
 	ok( !strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name" );
 	ok( !strcmp(temp_state_key->name, "allowedchars_in_keyname"), "Got key name with valid chars" );
-	ok( !strcmp(temp_state_key->_filename, "/usr/local/nagios/var/check_test/allowedchars_in_keyname"), "Got internal filename" );
+	ok( !strcmp(temp_state_key->_filename, state_path), "Got internal filename" );
 
 
 	/* Don't do this test just yet. Will die */
@@ -359,12 +362,13 @@ main (int argc, char **argv)
 
 	np_enable_state("funnykeyname", 54);
 	temp_state_key = this_monitoring_plugin->state;
+	sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/funnykeyname", (unsigned long)geteuid());
 	ok( !strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name" );
 	ok( !strcmp(temp_state_key->name, "funnykeyname"), "Got key name" );
 
 
 
-	ok( !strcmp(temp_state_key->_filename, "/usr/local/nagios/var/check_test/funnykeyname"), "Got internal filename" );
+	ok( !strcmp(temp_state_key->_filename, state_path), "Got internal filename" );
 	ok( temp_state_key->data_version==54, "Version set" );
 
 	temp_state_data = np_state_read();

+ 3 - 14
lib/utils_base.c

@@ -300,19 +300,6 @@ char *np_escaped_string (const char *string) {
 
 int np_check_if_root(void) { return (geteuid() == 0); }
 
-int np_warn_if_not_root(void) {
-	int status = np_check_if_root();
-	if(!status) {
-		printf(_("Warning: "));
-		printf(_("This plugin must be either run as root or setuid root.\n"));
-		printf(_("To run as root, you can use a tool like sudo.\n"));
-		printf(_("To set the setuid permissions, use the command:\n"));
-		/* XXX could we use something like progname? */
-		printf("\tchmod u+s yourpluginfile\n");
-	}
-	return status;
-}
-
 /*
  * Extract the value from key/value pairs, or return NULL. The value returned
  * can be free()ed.
@@ -489,7 +476,9 @@ void np_enable_state(char *keyname, int expected_data_version) {
 	this_state->state_data=NULL;
 
 	/* Calculate filename */
-	asprintf(&temp_filename, "%s/%s/%s", _np_state_calculate_location_prefix(), this_monitoring_plugin->plugin_name, this_state->name);
+	asprintf(&temp_filename, "%s/%lu/%s/%s",
+	    _np_state_calculate_location_prefix(), (unsigned long)geteuid(),
+	    this_monitoring_plugin->plugin_name, this_state->name);
 	this_state->_filename=temp_filename;
 
 	this_monitoring_plugin->state = this_state;

+ 0 - 3
lib/utils_base.h

@@ -75,9 +75,6 @@ void die (int, const char *, ...) __attribute__((noreturn,format(printf, 2, 3)))
 /* a simple check to see if we're running as root.  
  * returns zero on failure, nonzero on success */
 int np_check_if_root(void);
-/* and a helpful wrapper around that.  it returns the same status
- * code from the above function, in case it's helpful for testing */
-int np_warn_if_not_root(void);
 
 /* mp_suid() returns true if the real and effective uids differs, such as when
  * running a suid plugin */

+ 3 - 0
lib/utils_cmd.c

@@ -390,6 +390,9 @@ cmd_file_read ( char *filename, output *out, int flags)
 	
 	if(out)
 		out->lines = _cmd_fetch_output (fd, out, flags);
+	
+	if (close(fd) == -1)
+		die( STATE_UNKNOWN, _("Error closing %s: %s"), filename, strerror(errno) );
 
 	return 0;
 }

+ 1 - 4
plugins-root/check_dhcp.c

@@ -270,9 +270,6 @@ int main(int argc, char **argv){
 		usage4 (_("Could not parse arguments"));
 		}
 
-	/* this plugin almost certainly needs root permissions. */
-	np_warn_if_not_root();
-
 	/* create socket for DHCP communications */
 	dhcp_socket=create_dhcp_socket();
 
@@ -837,7 +834,7 @@ int add_dhcp_offer(struct in_addr source,dhcp_packet *offer_packet){
 		return ERROR;
 
 	/* process all DHCP options present in the packet */
-	for(x=4;x<MAX_DHCP_OPTIONS_LENGTH;){
+	for(x=4;x<MAX_DHCP_OPTIONS_LENGTH-1;){
 
 		if((int)offer_packet->options[x]==-1)
 			break;

+ 0 - 3
plugins-root/check_icmp.c

@@ -383,9 +383,6 @@ main(int argc, char **argv)
 	bindtextdomain (PACKAGE, LOCALEDIR);
 	textdomain (PACKAGE);
 
-	/* print a helpful error message if geteuid != 0 */
-	np_warn_if_not_root();
-
 	/* we only need to be setsuid when we get the sockets, so do
 	 * that before pointer magic (esp. on network data) */
 	icmp_sockerrno = udp_sockerrno = tcp_sockerrno = sockets = 0;

+ 2 - 1
plugins-scripts/Makefile.am

@@ -26,7 +26,8 @@ EXTRA_DIST=check_breeze.pl check_disk_smb.pl check_flexlm.pl check_ircd.pl \
 EDIT = sed \
   -e 's|[@]NP_VERSION[@]|$(NP_VERSION)|g' \
   -e 's|[@]TRUSTED_PATH[@]|$(with_trusted_path)|g' \
-  -e 's|[@]PERL[@]|$(PERL)|g'
+  -e 's|[@]PERL[@]|$(PERL)|g' \
+  -e 's|[@]libexecdir[@]|$(libexecdir)|g'
 
 TESTS_ENVIRONMENT=perl -I $(top_builddir) -I $(top_srcdir)
 

+ 1 - 0
plugins-scripts/check_breeze.pl

@@ -6,6 +6,7 @@ use Getopt::Long;
 use vars qw($opt_V $opt_h $opt_w $opt_c $opt_H $opt_C $PROGNAME);
 use FindBin;
 use lib "$FindBin::Bin";
+use lib '@libexecdir@';
 use utils qw(%ERRORS &print_revision &support &usage);
 
 $PROGNAME = "check_breeze";

+ 1 - 0
plugins-scripts/check_disk_smb.pl

@@ -26,6 +26,7 @@ use vars qw($opt_P $opt_V $opt_h $opt_H $opt_s $opt_W $opt_u $opt_p $opt_w $opt_
 use vars qw($PROGNAME);
 use FindBin;
 use lib "$FindBin::Bin";
+use lib '@libexecdir@';
 use utils qw($TIMEOUT %ERRORS &print_revision &support &usage);
 
 sub print_help ();

+ 3 - 1
plugins-scripts/check_file_age.pl

@@ -25,7 +25,9 @@ use English;
 use Getopt::Long;
 use File::stat;
 use vars qw($PROGNAME);
-use lib ".";
+use FindBin;
+use lib "$FindBin::Bin";
+use lib '@libexecdir@';
 use utils qw (%ERRORS &print_revision &support);
 
 sub print_help ();

+ 1 - 0
plugins-scripts/check_flexlm.pl

@@ -37,6 +37,7 @@ use Getopt::Long;
 use vars qw($opt_V $opt_h $opt_F $opt_t $verbose $PROGNAME);
 use FindBin;
 use lib "$FindBin::Bin";
+use lib '@libexecdir@';
 use utils qw(%ERRORS &print_revision &support &usage);
 
 $PROGNAME="check_flexlm";

+ 1 - 0
plugins-scripts/check_ifoperstatus.pl

@@ -37,6 +37,7 @@ use POSIX;
 use strict;
 use FindBin;
 use lib "$FindBin::Bin";
+use lib '@libexecdir@';
 use utils qw($TIMEOUT %ERRORS &print_revision &support);
 
 use Net::SNMP;

+ 2 - 1
plugins-scripts/check_ifstatus.pl

@@ -34,6 +34,7 @@ use POSIX;
 use strict;
 use FindBin;
 use lib "$FindBin::Bin";
+use lib '@libexecdir@';
 use utils qw($TIMEOUT %ERRORS &print_revision &support);
 
 use Net::SNMP;
@@ -220,7 +221,7 @@ foreach $key (keys %ifStatus) {
 			$ifexclude,
 			$ifunused);
    }
-my $perfdata = sprintf("up=%d,down=%d,dormant=%d,excluded=%d,unused=%d",$ifup,$ifdown,$ifdormant,$ifexclude,$ifunused);
+my $perfdata = sprintf("up=%d down=%d dormant=%d excluded=%d unused=%d",$ifup,$ifdown,$ifdormant,$ifexclude,$ifunused);
 print ("$state: $answer |$perfdata\n");
 exit $ERRORS{$state};
 

+ 1 - 0
plugins-scripts/check_ircd.pl

@@ -51,6 +51,7 @@ use vars qw($opt_V $opt_h $opt_t $opt_p $opt_H $opt_w $opt_c $verbose);
 use vars qw($PROGNAME);
 use FindBin;
 use lib "$FindBin::Bin";
+use lib '@libexecdir@';
 use utils qw($TIMEOUT %ERRORS &print_revision &support &usage);
 
 # ----------------------------------------------------[ Function Prototypes ]--

+ 1 - 0
plugins-scripts/check_mailq.pl

@@ -33,6 +33,7 @@ use vars qw($opt_V $opt_h $opt_v $verbose $PROGNAME $opt_w $opt_c $opt_t
 					%srcdomains %dstdomains);
 use FindBin;
 use lib "$FindBin::Bin";
+use lib '@libexecdir@';
 use utils qw(%ERRORS &print_revision &support &usage );
 
 

+ 3 - 1
plugins-scripts/check_mssql.pl

@@ -29,7 +29,9 @@
 use DBI;
 use DBD::Sybase;
 use Getopt::Long;
-use lib ".";
+use FindBin;
+use lib "$FindBin::Bin";
+use lib '@libexecdir@';
 use utils qw($TIMEOUT %ERRORS &print_revision &support);
 use strict;
 

+ 1 - 0
plugins-scripts/check_netdns.pl

@@ -29,6 +29,7 @@ use Getopt::Long;
 use Net::DNS;
 use FindBin;
 use lib "$FindBin::Bin";
+use lib '@libexecdir@';
 use utils ;
 
 my $PROGNAME = "check_netdns";

+ 1 - 0
plugins-scripts/check_rpc.pl

@@ -22,6 +22,7 @@
 use strict;
 use FindBin;
 use lib "$FindBin::Bin";
+use lib '@libexecdir@';
 use utils qw($TIMEOUT %ERRORS &print_revision &support);
 use vars qw($PROGNAME);
 my ($verbose,@proto,%prognum,$host,$response,$prognum,$port,$cmd,$progver,$state);

+ 1 - 0
plugins-scripts/check_wave.pl

@@ -5,6 +5,7 @@
 use strict;
 use FindBin;
 use lib "$FindBin::Bin";
+use lib '@libexecdir@';
 use utils qw($TIMEOUT %ERRORS &print_revision &support);
 use vars qw($PROGNAME);
 use Getopt::Long;

+ 3 - 0
plugins/check_apt.c

@@ -223,6 +223,9 @@ int run_upgrade(int *pkgcount, int *secpkgcount){
 	regex_t ireg, ereg, sreg;
 	char *cmdline=NULL, rerrbuf[64];
 
+	/* initialize ereg as it is possible it is printed while uninitialized */
+	memset(&ereg, "\0", sizeof(ereg.buffer));
+
 	if(upgrade==NO_UPGRADE) return STATE_OK;
 
 	/* compile the regexps */

+ 3 - 3
plugins/check_dbi.c

@@ -215,7 +215,7 @@ main (int argc, char **argv)
 	}
 
 	if (dbi_conn_connect (conn) < 0) {
-		np_dbi_print_error (conn, "UNKOWN - failed to connect to database");
+		np_dbi_print_error (conn, "UNKNOWN - failed to connect to database");
 		return STATE_UNKNOWN;
 	}
 
@@ -241,7 +241,7 @@ main (int argc, char **argv)
 			printf ("Selecting database '%s'\n", np_dbi_database);
 
 		if (dbi_conn_select_db (conn, np_dbi_database)) {
-			np_dbi_print_error (conn, "UNKOWN - failed to select database '%s'",
+			np_dbi_print_error (conn, "UNKNOWN - failed to select database '%s'",
 					np_dbi_database);
 			return STATE_UNKNOWN;
 		}
@@ -456,7 +456,7 @@ process_arguments (int argc, char **argv)
 				new = realloc (np_dbi_options,
 						(np_dbi_options_num + 1) * sizeof (*new));
 				if (! new) {
-					printf ("UNKOWN - failed to reallocate memory\n");
+					printf ("UNKNOWN - failed to reallocate memory\n");
 					exit (STATE_UNKNOWN);
 				}
 

+ 17 - 1
plugins/check_dns.c

@@ -242,7 +242,23 @@ main (int argc, char **argv)
     }
     printf (ngettext("%.3f second response time", "%.3f seconds response time", elapsed_time), elapsed_time);
     printf (_(". %s returns %s"), query_address, address);
-    printf ("|%s\n", fperfdata ("time", elapsed_time, "s", FALSE, 0, FALSE, 0, TRUE, 0, FALSE, 0));
+    if ((time_thresholds->warning != NULL) && (time_thresholds->critical != NULL)) {
+      printf ("|%s\n", fperfdata ("time", elapsed_time, "s",
+                                  TRUE, time_thresholds->warning->end,
+                                  TRUE, time_thresholds->critical->end,
+                                  TRUE, 0, FALSE, 0));
+    } else if ((time_thresholds->warning == NULL) && (time_thresholds->critical != NULL)) {
+      printf ("|%s\n", fperfdata ("time", elapsed_time, "s",
+                                  FALSE, 0,
+                                  TRUE, time_thresholds->critical->end,
+                                  TRUE, 0, FALSE, 0));
+    } else if ((time_thresholds->warning != NULL) && (time_thresholds->critical == NULL)) {
+      printf ("|%s\n", fperfdata ("time", elapsed_time, "s",
+                                  TRUE, time_thresholds->warning->end,
+                                  FALSE, 0,
+                                  TRUE, 0, FALSE, 0));
+    } else
+      printf ("|%s\n", fperfdata ("time", elapsed_time, "s", FALSE, 0, FALSE, 0, TRUE, 0, FALSE, 0));
   }
   else if (result == STATE_WARNING)
     printf (_("DNS WARNING - %s\n"),

+ 24 - 6
plugins/check_hpjd.c

@@ -39,7 +39,7 @@ const char *email = "devel@monitoring-plugins.org";
 #include "netutils.h"
 
 #define DEFAULT_COMMUNITY "public"
-
+#define DEFAULT_PORT "161"
 
 const char *option_summary = "-H host [-C community]\n";
 
@@ -66,6 +66,7 @@ void print_usage (void);
 
 char *community = NULL;
 char *address = NULL;
+char *port = NULL;
 
 int
 main (int argc, char **argv)
@@ -119,8 +120,8 @@ main (int argc, char **argv)
 		 HPJD_GD_DOOR_OPEN, HPJD_GD_PAPER_OUTPUT, HPJD_GD_STATUS_DISPLAY);
 
 	/* get the command to run */
-	sprintf (command_line, "%s -OQa -m : -v 1 -c %s %s %s", PATH_TO_SNMPGET, community,
-									address, query_string);
+	sprintf (command_line, "%s -OQa -m : -v 1 -c %s %s:%hd %s", PATH_TO_SNMPGET, community,
+									address, port, query_string);
 
 	/* run the command */
 	child_process = spopen (command_line);
@@ -313,7 +314,7 @@ process_arguments (int argc, char **argv)
 		{"community", required_argument, 0, 'C'},
 /*  		{"critical",       required_argument,0,'c'}, */
 /*  		{"warning",        required_argument,0,'w'}, */
-/*  		{"port",           required_argument,0,'P'}, */
+  		{"port", required_argument,0,'p'}, 
 		{"version", no_argument, 0, 'V'},
 		{"help", no_argument, 0, 'h'},
 		{0, 0, 0, 0}
@@ -324,7 +325,7 @@ process_arguments (int argc, char **argv)
 
 
 	while (1) {
-		c = getopt_long (argc, argv, "+hVH:C:", longopts, &option);
+		c = getopt_long (argc, argv, "+hVH:C:p:", longopts, &option);
 
 		if (c == -1 || c == EOF || c == 1)
 			break;
@@ -341,6 +342,12 @@ process_arguments (int argc, char **argv)
 		case 'C':									/* community */
 			community = strscpy (community, optarg);
 			break;
+		case 'p':
+			if (!is_intpos(optarg))
+				usage2 (_("Port must be a positive short integer"), optarg);
+			else
+				port = atoi(optarg);
+			break;
 		case 'V':									/* version */
 			print_revision (progname, NP_VERSION);
 			exit (STATE_OK);
@@ -369,6 +376,13 @@ process_arguments (int argc, char **argv)
 			community = strdup (DEFAULT_COMMUNITY);
 	}
 
+	if (port == NULL) {
+		if (argv[c] != NULL )
+			port = argv[c];
+		else
+			port = atoi (DEFAULT_PORT);
+	}
+
 	return validate_arguments ();
 }
 
@@ -402,6 +416,10 @@ print_help (void)
 	printf ("    %s", _("The SNMP community name "));
 	printf (_("(default=%s)"), DEFAULT_COMMUNITY);
 	printf ("\n");
+	printf (" %s\n", "-p, --port=STRING");
+	printf ("    %s", _("Specify the port to check "));
+	printf (_("(default=%s)"), DEFAULT_PORT);
+	printf ("\n");
 
 	printf (UT_SUPPORT);
 }
@@ -412,5 +430,5 @@ void
 print_usage (void)
 {
   printf ("%s\n", _("Usage:"));
-	printf ("%s -H host [-C community]\n", progname);
+	printf ("%s -H host [-C community] [-p port]\n", progname);
 }

+ 6 - 4
plugins/check_http.c

@@ -1243,6 +1243,7 @@ redir (char *pos, char *status_line)
   if (addr == NULL)
     die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n"));
 
+  memset(addr, 0, MAX_IPV4_HOSTLENGTH);
   url = malloc (strcspn (pos, "\r\n"));
   if (url == NULL)
     die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
@@ -1333,8 +1334,8 @@ redir (char *pos, char *status_line)
          max_depth, type, addr, i, url, (display_html ? "</A>" : ""));
 
   if (server_port==i &&
-      !strcmp(server_address, addr) &&
-      (host_name && !strcmp(host_name, addr)) &&
+      !strncmp(server_address, addr, MAX_IPV4_HOSTLENGTH) &&
+      (host_name && !strncmp(host_name, addr, MAX_IPV4_HOSTLENGTH)) &&
       !strcmp(server_url, url))
     die (STATE_WARNING,
          _("HTTP WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
@@ -1343,11 +1344,11 @@ redir (char *pos, char *status_line)
   strcpy (server_type, type);
 
   free (host_name);
-  host_name = strdup (addr);
+  host_name = strndup (addr, MAX_IPV4_HOSTLENGTH);
 
   if (!(followsticky & STICKY_HOST)) {
     free (server_address);
-    server_address = strdup (addr);
+    server_address = strndup (addr, MAX_IPV4_HOSTLENGTH);
   }
   if (!(followsticky & STICKY_PORT)) {
     server_port = i;
@@ -1366,6 +1367,7 @@ redir (char *pos, char *status_line)
     printf (_("Redirection to %s://%s:%d%s\n"), server_type,
             host_name ? host_name : server_address, server_port, server_url);
 
+  free(addr);
   check_http ();
 }
 

+ 1 - 1
plugins/check_ide_smart.c

@@ -419,7 +419,7 @@ nagios (values_t * p, thresholds_t * t)
 		status=STATE_OK;
 		break;
 	default:
-		printf (_("ERROR - Status '%d' unkown. %d/%d tests passed\n"), status,
+		printf (_("ERROR - Status '%d' unknown. %d/%d tests passed\n"), status,
 						passed, total);
 		status = STATE_UNKNOWN;
 		break;

+ 1 - 1
plugins/check_mrtg.c

@@ -356,7 +356,7 @@ print_help (void)
 	printf (" %s\n", _("This plugin is useful for monitoring MRTG data that does not correspond to"));
   printf (" %s\n", _("bandwidth usage.  (Use the check_mrtgtraf plugin for monitoring bandwidth)."));
   printf (" %s\n", _("It can be used to monitor any kind of data that MRTG is monitoring - errors,"));
-  printf (" %s\n", _("packets/sec, etc.  I use MRTG in conjuction with the Novell NLM that allows"));
+  printf (" %s\n", _("packets/sec, etc.  I use MRTG in conjunction with the Novell NLM that allows"));
   printf (" %s\n", _("me to track processor utilization, user connections, drive space, etc and"));
   printf (" %s\n\n", _("this plugin works well for monitoring that kind of data as well."));
 

+ 20 - 2
plugins/check_mysql.c

@@ -42,6 +42,7 @@ const char *email = "devel@monitoring-plugins.org";
 #include "netutils.h"
 
 #include <mysql.h>
+#include <mysqld_error.h>
 #include <errmsg.h>
 
 char *db_user = NULL;
@@ -59,6 +60,7 @@ char *opt_file = NULL;
 char *opt_group = NULL;
 unsigned int db_port = MYSQL_PORT;
 int check_slave = 0, warn_sec = 0, crit_sec = 0;
+int ignore_auth = 0;
 int verbose = 0;
 
 static double warning_time = 0;
@@ -136,7 +138,16 @@ main (int argc, char **argv)
 		mysql_ssl_set(&mysql,key,cert,ca_cert,ca_dir,ciphers);
 	/* establish a connection to the server and error checking */
 	if (!mysql_real_connect(&mysql,db_host,db_user,db_pass,db,db_port,db_socket,0)) {
-		if (mysql_errno (&mysql) == CR_UNKNOWN_HOST)
+		if (ignore_auth && mysql_errno (&mysql) == ER_ACCESS_DENIED_ERROR)
+		{
+			printf("MySQL OK - Version: %s (protocol %d)\n",
+				mysql_get_server_info(&mysql),
+				mysql_get_proto_info(&mysql)
+			);
+			mysql_close (&mysql);
+			return STATE_OK;
+		}
+		else if (mysql_errno (&mysql) == CR_UNKNOWN_HOST)
 			die (STATE_WARNING, "%s\n", mysql_error (&mysql));
 		else if (mysql_errno (&mysql) == CR_VERSION_ERROR)
 			die (STATE_WARNING, "%s\n", mysql_error (&mysql));
@@ -341,6 +352,7 @@ process_arguments (int argc, char **argv)
 		{"critical", required_argument, 0, 'c'},
 		{"warning", required_argument, 0, 'w'},
 		{"check-slave", no_argument, 0, 'S'},
+		{"ignore-auth", no_argument, 0, 'n'},
 		{"verbose", no_argument, 0, 'v'},
 		{"version", no_argument, 0, 'V'},
 		{"help", no_argument, 0, 'h'},
@@ -357,7 +369,7 @@ process_arguments (int argc, char **argv)
 		return ERROR;
 
 	while (1) {
-		c = getopt_long (argc, argv, "hlvVSP:p:u:d:H:s:c:w:a:k:C:D:L:f:g:", longopts, &option);
+		c = getopt_long (argc, argv, "hlvVnSP:p:u:d:H:s:c:w:a:k:C:D:L:f:g:", longopts, &option);
 
 		if (c == -1 || c == EOF)
 			break;
@@ -419,6 +431,9 @@ process_arguments (int argc, char **argv)
 		case 'S':
 			check_slave = 1;							/* check-slave */
 			break;
+		case 'n':
+			ignore_auth = 1;							/* ignore-auth */
+			break;
 		case 'w':
 			warning = optarg;
 			warning_time = strtod (warning, NULL);
@@ -506,6 +521,9 @@ print_help (void)
 	printf (UT_EXTRA_OPTS);
 
   printf (UT_HOST_PORT, 'P', myport);
+  printf (" %s\n", "-n, --ignore-auth");
+  printf ("    %s\n", _("Ignore authentication failure and check for mysql connectivity only"));
+
   printf (" %s\n", "-s, --socket=STRING");
   printf ("    %s\n", _("Use the specified socket (has no effect if -H is used)"));
 

+ 2 - 2
plugins/check_nt.c

@@ -293,10 +293,10 @@ int main(int argc, char **argv){
 
 		/* Divisor should be 1048567, not 3044515, as we are measuring "Commit Charge" here,
 		which equals RAM + Pagefiles. */
-		xasprintf(&output_message,_("Memory usage: total:%.2f Mb - used: %.2f Mb (%.0f%%) - free: %.2f Mb (%.0f%%)"),
+		xasprintf(&output_message,_("Memory usage: total:%.2f MB - used: %.2f MB (%.0f%%) - free: %.2f MB (%.0f%%)"),
 		  mem_commitLimit / 1048567, mem_commitByte / 1048567, percent_used_space,
 		  (mem_commitLimit - mem_commitByte) / 1048567, (mem_commitLimit - mem_commitByte) / mem_commitLimit * 100);
-		xasprintf(&perfdata,_("'Memory usage'=%.2fMb;%.2f;%.2f;0.00;%.2f"), mem_commitByte / 1048567,
+		xasprintf(&perfdata,_("'Memory usage'=%.2fMB;%.2f;%.2f;0.00;%.2f"), mem_commitByte / 1048567,
 		  warning_used_space / 1048567, critical_used_space / 1048567, mem_commitLimit / 1048567);
 
 		return_code=STATE_OK;

+ 11 - 2
plugins/check_ntp.c

@@ -517,13 +517,14 @@ setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq){
 double jitter_request(const char *host, int *status){
 	int conn=-1, i, npeers=0, num_candidates=0, syncsource_found=0;
 	int run=0, min_peer_sel=PEER_INCLUDED, num_selected=0, num_valid=0;
-	int peers_size=0, peer_offset=0;
+	int peers_size=0, peer_offset=0, bytes_read=0;
 	ntp_assoc_status_pair *peers=NULL;
 	ntp_control_message req;
 	const char *getvar = "jitter";
 	double rval = 0.0, jitter = -1.0;
 	char *startofvalue=NULL, *nptr=NULL;
 	void *tmp;
+	int ntp_cm_ints = sizeof(uint16_t) * 5 + sizeof(uint8_t) * 2;
 
 	/* Long-winded explanation:
 	 * Getting the jitter requires a number of steps:
@@ -608,7 +609,15 @@ double jitter_request(const char *host, int *status){
 
 				req.count = htons(MAX_CM_SIZE);
 				DBG(printf("recieving READVAR response...\n"));
-				read(conn, &req, SIZEOF_NTPCM(req));
+
+				/* cov-66524 - req.data not null terminated before usage. Also covers verifying struct was returned correctly*/
+				if ((bytes_read = read(conn, &req, SIZEOF_NTPCM(req))) == -1)
+					die(STATE_UNKNOWN, _("Cannot read from socket: %s"), strerror(errno));
+				if (bytes_read != ntp_cm_ints + req.count)
+					die(STATE_UNKNOWN, _("Invalid NTP response: %d bytes read does not equal %d plus %d data segment"), bytes_read, ntp_cm_ints, req.count); 
+				/* else null terminate */
+				strncpy(req.data[req.count], "\0", 1);
+
 				DBG(print_ntp_control_message(&req));
 
 				if(req.op&REM_ERROR && strstr(getvar, "jitter")) {

+ 37 - 12
plugins/check_ntp_peer.c

@@ -560,7 +560,7 @@ char *perfd_truechimers (int num_truechimers)
 }
 
 int main(int argc, char *argv[]){
-	int result, offset_result, stratum, num_truechimers;
+	int result, offset_result, stratum, num_truechimers, oresult, jresult, sresult, tresult;
 	double offset=0, jitter=0;
 	char *result_line, *perfdata_line;
 
@@ -597,15 +597,19 @@ int main(int argc, char *argv[]){
 			result = STATE_UNKNOWN;
 		result = max_state_alt(result, get_status(fabs(offset), offset_thresholds));
 	}
-
+	oresult = result;
+	
 	if(do_truechimers)
-		result = max_state_alt(result, get_status(num_truechimers, truechimer_thresholds));
+		tresult = get_status(num_truechimers, truechimer_thresholds);
+		result = max_state_alt(result, tresult);
 
 	if(do_stratum)
-		result = max_state_alt(result, get_status(stratum, stratum_thresholds));
+		sresult = get_status(stratum, stratum_thresholds);
+		result = max_state_alt(result, sresult);
 
 	if(do_jitter)
-		result = max_state_alt(result, get_status(jitter, jitter_thresholds));
+		jresult = get_status(jitter, jitter_thresholds);
+		result = max_state_alt(result, jresult);
 
 	switch (result) {
 		case STATE_CRITICAL :
@@ -629,20 +633,43 @@ int main(int argc, char *argv[]){
 	if(offset_result == STATE_UNKNOWN){
 		xasprintf(&result_line, "%s %s", result_line, _("Offset unknown"));
 		xasprintf(&perfdata_line, "");
+	} else if (oresult == STATE_WARNING) {
+		xasprintf(&result_line, "%s %s %.10g secs (WARNING)", result_line, _("Offset"), offset);
+	} else if (oresult == STATE_CRITICAL) {
+		xasprintf(&result_line, "%s %s %.10g secs (CRITICAL)", result_line, _("Offset"), offset);
 	} else {
 		xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset);
-		xasprintf(&perfdata_line, "%s", perfd_offset(offset));
-	}
+	}	
+	xasprintf(&perfdata_line, "%s", perfd_offset(offset));
+	
 	if (do_jitter) {
-		xasprintf(&result_line, "%s, jitter=%f", result_line, jitter);
+		if (jresult == STATE_WARNING) {
+			xasprintf(&result_line, "%s, jitter=%f (WARNING)", result_line, jitter);
+		} else if (jresult == STATE_CRITICAL) {
+			xasprintf(&result_line, "%s, jitter=%f (CRITICAL)", result_line, jitter);
+		} else {
+			xasprintf(&result_line, "%s, jitter=%f", result_line, jitter);
+		}
 		xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_jitter(jitter));
 	}
 	if (do_stratum) {
-		xasprintf(&result_line, "%s, stratum=%i", result_line, stratum);
+		if (sresult == STATE_WARNING) {
+			xasprintf(&result_line, "%s, stratum=%i (WARNING)", result_line, stratum);
+		} else if (sresult == STATE_CRITICAL) {
+			xasprintf(&result_line, "%s, stratum=%i (CRITICAL)", result_line, stratum);
+		} else {
+			xasprintf(&result_line, "%s, stratum=%i", result_line, stratum);
+		}
 		xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_stratum(stratum));
 	}
 	if (do_truechimers) {
-		xasprintf(&result_line, "%s, truechimers=%i", result_line, num_truechimers);
+		if (tresult == STATE_WARNING) {
+			xasprintf(&result_line, "%s, truechimers=%i (WARNING)", result_line, num_truechimers);
+		} else if (tresult == STATE_CRITICAL) {
+			xasprintf(&result_line, "%s, truechimers=%i (CRITICAL)", result_line, num_truechimers);
+		} else {
+			xasprintf(&result_line, "%s, truechimers=%i", result_line, num_truechimers);
+		}
 		xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_truechimers(num_truechimers));
 	}
 	printf("%s|%s\n", result_line, perfdata_line);
@@ -651,8 +678,6 @@ int main(int argc, char *argv[]){
 	return result;
 }
 
-
-
 void print_help(void){
 	print_revision(progname, NP_VERSION);
 

+ 12 - 3
plugins/check_ntp_time.c

@@ -48,6 +48,7 @@ static int verbose=0;
 static int quiet=0;
 static char *owarn="60";
 static char *ocrit="120";
+static int time_offset=0;
 
 int process_arguments (int, char **);
 thresholds *offset_thresholds = NULL;
@@ -400,7 +401,7 @@ double offset_request(const char *host, int *status){
 				gettimeofday(&recv_time, NULL);
 				DBG(print_ntp_message(&req[i]));
 				respnum=servers[i].num_responses++;
-				servers[i].offset[respnum]=calc_offset(&req[i], &recv_time);
+				servers[i].offset[respnum]=calc_offset(&req[i], &recv_time)+time_offset;
 				if(verbose) {
 					printf("offset %.10g\n", servers[i].offset[respnum]);
 				}
@@ -455,6 +456,7 @@ int process_arguments(int argc, char **argv){
 		{"use-ipv4", no_argument, 0, '4'},
 		{"use-ipv6", no_argument, 0, '6'},
 		{"quiet", no_argument, 0, 'q'},
+		{"time-offset", optional_argument, 0, 'o'},
 		{"warning", required_argument, 0, 'w'},
 		{"critical", required_argument, 0, 'c'},
 		{"timeout", required_argument, 0, 't'},
@@ -468,7 +470,7 @@ int process_arguments(int argc, char **argv){
 		usage ("\n");
 
 	while (1) {
-		c = getopt_long (argc, argv, "Vhv46qw:c:t:H:p:", longopts, &option);
+		c = getopt_long (argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option);
 		if (c == -1 || c == EOF || c == 1)
 			break;
 
@@ -504,6 +506,9 @@ int process_arguments(int argc, char **argv){
 		case 't':
 			socket_timeout=atoi(optarg);
 			break;
+		case 'o':
+			time_offset=atoi(optarg);
+                        break;
 		case '4':
 			address_family = AF_INET;
 			break;
@@ -616,6 +621,8 @@ void print_help(void){
 	printf ("    %s\n", _("Offset to result in warning status (seconds)"));
 	printf (" %s\n", "-c, --critical=THRESHOLD");
 	printf ("    %s\n", _("Offset to result in critical status (seconds)"));
+	printf (" %s\n", "-o, --time_offset=INTEGER");
+	printf ("    %s\n", _("Expected offset of the ntp server relative to local server (seconds)"));
 	printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
 	printf (UT_VERBOSE);
 
@@ -628,6 +635,8 @@ void print_help(void){
 	printf("%s\n", _("Notes:"));
 	printf(" %s\n", _("If you'd rather want to monitor an NTP server, please use"));
 	printf(" %s\n", _("check_ntp_peer."));
+	printf(" %s\n", _("--time-offset is usefull for compensating for servers with known"));
+	printf(" %s\n", _("and expected clock skew."));
 	printf("\n");
 	printf(UT_THRESHOLDS_NOTES);
 
@@ -642,6 +651,6 @@ void
 print_usage(void)
 {
 	printf ("%s\n", _("Usage:"));
-	printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [-v verbose]\n", progname);
+	printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [-v verbose] [-o <time offset>]\n", progname);
 }
 

+ 28 - 21
plugins/check_radius.c

@@ -36,9 +36,10 @@ const char *email = "devel@monitoring-plugins.org";
 #include "utils.h"
 #include "netutils.h"
 
-#ifdef HAVE_LIBRADIUSCLIENT_NG
+#if defined(HAVE_LIBFREERADIUS_CLIENT)
+#include <freeradius-client.h>
+#elif defined(HAVE_LIBRADIUSCLIENT_NG)
 #include <radiusclient-ng.h>
-rc_handle *rch = NULL;
 #else
 #include <radiusclient.h>
 #endif
@@ -47,11 +48,14 @@ int process_arguments (int, char **);
 void print_help (void);
 void print_usage (void);
 
-/* libradiusclient(-ng) wrapper functions */
-#ifdef HAVE_LIBRADIUSCLIENT_NG
+#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG)
 #define my_rc_conf_str(a) rc_conf_str(rch,a)
 #define my_rc_send_server(a,b) rc_send_server(rch,a,b)
+#ifdef HAVE_LIBFREERADIUS_CLIENT
+#define my_rc_buildreq(a,b,c,d,e,f) rc_buildreq(rch,a,b,c,d,(a)->secret,e,f)
+#else
 #define my_rc_buildreq(a,b,c,d,e,f) rc_buildreq(rch,a,b,c,d,e,f)
+#endif
 #define my_rc_own_ipaddress() rc_own_ipaddress(rch)
 #define my_rc_avpair_add(a,b,c,d) rc_avpair_add(rch,a,b,c,-1,d)
 #define my_rc_read_dictionary(a) rc_read_dictionary(rch, a)
@@ -72,6 +76,10 @@ void print_usage (void);
 
 int my_rc_read_config(char *);
 
+#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG)
+rc_handle *rch = NULL;
+#endif
+
 char *server = NULL;
 char *username = NULL;
 char *password = NULL;
@@ -142,11 +150,10 @@ Please note that all tags must be lowercase to use the DocBook XML DTD.
 int
 main (int argc, char **argv)
 {
-	UINT4 service;
 	char msg[BUFFER_LEN];
 	SEND_DATA data;
 	int result = STATE_UNKNOWN;
-	UINT4 client_id;
+	uint32_t client_id, service;
 	char *str;
 
 	setlocale (LC_ALL, "");
@@ -162,7 +169,7 @@ main (int argc, char **argv)
 	str = strdup ("dictionary");
 	if ((config_file && my_rc_read_config (config_file)) ||
 			my_rc_read_dictionary (my_rc_conf_str (str)))
-		die (STATE_UNKNOWN, _("Config file error"));
+		die (STATE_UNKNOWN, _("Config file error\n"));
 
 	service = PW_AUTHENTICATE_ONLY;
 
@@ -171,24 +178,24 @@ main (int argc, char **argv)
 				my_rc_avpair_add (&data.send_pairs, PW_USER_NAME, username, 0) &&
 				my_rc_avpair_add (&data.send_pairs, PW_USER_PASSWORD, password, 0)
 				))
-		die (STATE_UNKNOWN, _("Out of Memory?"));
+		die (STATE_UNKNOWN, _("Out of Memory?\n"));
 
 	if (nasid != NULL) {
 		if (!(my_rc_avpair_add (&data.send_pairs, PW_NAS_IDENTIFIER, nasid, 0)))
-			die (STATE_UNKNOWN, _("Invalid NAS-Identifier"));
+			die (STATE_UNKNOWN, _("Invalid NAS-Identifier\n"));
 	}
 
 	if (nasipaddress != NULL) {
 		if (rc_good_ipaddr (nasipaddress))
-			die (STATE_UNKNOWN, _("Invalid NAS-IP-Address"));
+			die (STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
 		if ((client_id = rc_get_ipaddr(nasipaddress)) == 0)
-			die (STATE_UNKNOWN, _("Invalid NAS-IP-Address"));
+			die (STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
 	} else {
 		if ((client_id = my_rc_own_ipaddress ()) == 0)
-			die (STATE_UNKNOWN, _("Can't find local IP for NAS-IP-Address"));
+			die (STATE_UNKNOWN, _("Can't find local IP for NAS-IP-Address\n"));
 	}
 	if (my_rc_avpair_add (&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0) == NULL)
-		die (STATE_UNKNOWN, _("Invalid NAS-IP-Address"));
+		die (STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
 
 	my_rc_buildreq (&data, PW_ACCESS_REQUEST, server, port, (int)timeout_interval,
 	             retries);
@@ -199,19 +206,19 @@ main (int argc, char **argv)
 		rc_avpair_free (data.receive_pairs);
 
 	if (result == TIMEOUT_RC)
-		die (STATE_CRITICAL, _("Timeout"));
+		die (STATE_CRITICAL, _("Timeout\n"));
 	if (result == ERROR_RC)
-		die (STATE_CRITICAL, _("Auth Error"));
+		die (STATE_CRITICAL, _("Auth Error\n"));
 	if (result == REJECT_RC)
-		die (STATE_WARNING, _("Auth Failed"));
+		die (STATE_WARNING, _("Auth Failed\n"));
 	if (result == BADRESP_RC)
-		die (STATE_WARNING, _("Bad Response"));
+		die (STATE_WARNING, _("Bad Response\n"));
 	if (expect && !strstr (msg, expect))
-		die (STATE_WARNING, "%s", msg);
+		die (STATE_WARNING, "%s\n", msg);
 	if (result == OK_RC)
-		die (STATE_OK, _("Auth OK"));
+		die (STATE_OK, _("Auth OK\n"));
 	(void)snprintf(msg, sizeof(msg), _("Unexpected result code %d"), result);
-	die (STATE_UNKNOWN, "%s", msg);
+	die (STATE_UNKNOWN, "%s\n", msg);
 }
 
 
@@ -392,7 +399,7 @@ print_usage (void)
 
 int my_rc_read_config(char * a)
 {
-#ifdef HAVE_LIBRADIUSCLIENT_NG
+#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG)
 	rch = rc_read_config(a);
 	return (rch == NULL) ? 1 : 0;
 #else

+ 1 - 0
plugins/check_real.c

@@ -178,6 +178,7 @@ main (int argc, char **argv)
 
 		/* watch for the REAL connection string */
 		result = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0);
+		buffer[result] = "\0"; /* null terminate recieved buffer */
 
 		/* return a CRITICAL status if we couldn't read any data */
 		if (result == -1) {

+ 20 - 4
plugins/check_ssh.c

@@ -46,6 +46,7 @@ const char *email = "devel@monitoring-plugins.org";
 int port = -1;
 char *server_name = NULL;
 char *remote_version = NULL;
+char *remote_protocol = NULL;
 int verbose = FALSE;
 
 int process_arguments (int, char **);
@@ -53,7 +54,7 @@ int validate_arguments (void);
 void print_help (void);
 void print_usage (void);
 
-int ssh_connect (char *haddr, int hport, char *remote_version);
+int ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol);
 
 
 
@@ -78,7 +79,7 @@ main (int argc, char **argv)
 	alarm (socket_timeout);
 
 	/* ssh_connect exits if error is found */
-	result = ssh_connect (server_name, port, remote_version);
+	result = ssh_connect (server_name, port, remote_version, remote_protocol);
 
 	alarm (0);
 
@@ -105,6 +106,7 @@ process_arguments (int argc, char **argv)
 		{"timeout", required_argument, 0, 't'},
 		{"verbose", no_argument, 0, 'v'},
 		{"remote-version", required_argument, 0, 'r'},
+		{"remote-protcol", required_argument, 0, 'P'},
 		{0, 0, 0, 0}
 	};
 
@@ -116,7 +118,7 @@ process_arguments (int argc, char **argv)
 			strcpy (argv[c], "-t");
 
 	while (1) {
-		c = getopt_long (argc, argv, "+Vhv46t:r:H:p:", longopts, &option);
+		c = getopt_long (argc, argv, "+Vhv46t:r:H:p:P:", longopts, &option);
 
 		if (c == -1 || c == EOF)
 			break;
@@ -152,6 +154,9 @@ process_arguments (int argc, char **argv)
 		case 'r':									/* remote version */
 			remote_version = optarg;
 			break;
+		case 'P':									/* remote version */
+			remote_protocol = optarg;
+			break;
 		case 'H':									/* host */
 			if (is_host (optarg) == FALSE)
 				usage2 (_("Invalid hostname/address"), optarg);
@@ -206,7 +211,7 @@ validate_arguments (void)
 
 
 int
-ssh_connect (char *haddr, int hport, char *remote_version)
+ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol)
 {
 	int sd;
 	int result;
@@ -254,6 +259,14 @@ ssh_connect (char *haddr, int hport, char *remote_version)
 			exit (STATE_WARNING);
 		}
 
+		if (remote_protocol && strcmp(remote_protocol, ssh_proto)) {
+			printf
+				(_("SSH WARNING - %s (protocol %s) protocol version mismatch, expected '%s'\n"),
+				 ssh_server, ssh_proto, remote_protocol);
+			close(sd);
+			exit (STATE_WARNING);
+		}
+
 		elapsed_time = (double)deltime(tv) / 1.0e6;
 
 		printf
@@ -296,6 +309,9 @@ print_help (void)
 	printf (" %s\n", "-r, --remote-version=STRING");
   printf ("    %s\n", _("Warn if string doesn't match expected server version (ex: OpenSSH_3.9p1)"));
 
+	printf (" %s\n", "-P, --remote-protocol=STRING");
+  printf ("    %s\n", _("Warn if protocol doesn't match expected protocol version (ex: 2.0)"));
+
 	printf (UT_VERBOSE);
 
 	printf (UT_SUPPORT);

+ 8 - 4
plugins/check_tcp.c

@@ -32,13 +32,12 @@ char *progname;
 const char *copyright = "1999-2008";
 const char *email = "devel@monitoring-plugins.org";
 
-#include <ctype.h>
-
 #include "common.h"
 #include "netutils.h"
 #include "utils.h"
 #include "utils_tcp.h"
 
+#include <ctype.h>
 #include <sys/select.h>
 
 #ifdef HAVE_SSL
@@ -354,8 +353,13 @@ main (int argc, char **argv)
 			printf("Unexpected response from host/socket on ");
 		else
 			printf("%.3f second response time on ", elapsed_time);
-		if(server_address[0] != '/')
-			printf("port %d", server_port);
+		if(server_address[0] != '/') {
+			if (host_specified)
+				printf("%s port %d",
+				       server_address, server_port);
+			else
+				printf("port %d", server_port);
+		}
 		else
 			printf("socket %s", server_address);
 	}

+ 3 - 3
plugins/check_ups.c

@@ -66,7 +66,7 @@ enum {
 #define UPSSTATUS_BOOST    512
 #define UPSSTATUS_CHRG    1024
 #define UPSSTATUS_DISCHRG 2048
-#define UPSSTATUS_UNKOWN  4096
+#define UPSSTATUS_UNKNOWN  4096
 
 enum { NOSUCHVAR = ERROR-1 };
 
@@ -181,7 +181,7 @@ main (int argc, char **argv)
 			if (status & UPSSTATUS_DISCHRG) {
 				xasprintf (&ups_status, "%s%s", ups_status, _(", Discharging"));
 			}
-			if (status & UPSSTATUS_UNKOWN) {
+			if (status & UPSSTATUS_UNKNOWN) {
 				xasprintf (&ups_status, "%s%s", ups_status, _(", Unknown"));
 			}
 		}
@@ -379,7 +379,7 @@ determine_status (void)
 		else if (!strcmp (ptr, "DISCHRG"))
 			status |= UPSSTATUS_DISCHRG;
 		else
-			status |= UPSSTATUS_UNKOWN;
+			status |= UPSSTATUS_UNKNOWN;
 	}
 
 	return OK;

+ 5 - 6
plugins/negate.c

@@ -35,16 +35,16 @@ const char *email = "devel@monitoring-plugins.org";
 
 #define DEFAULT_TIMEOUT 11
 
-#include <ctype.h>
-
 #include "common.h"
 #include "utils.h"
 #include "utils_cmd.h"
 
+#include <ctype.h>
+
 /* char *command_line; */
 
 static const char **process_arguments (int, char **);
-int validate_arguments (char **);
+void validate_arguments (char **);
 void print_help (void);
 void print_usage (void);
 int subst_text = FALSE;
@@ -98,8 +98,7 @@ main (int argc, char **argv)
 		die (max_state_alt (result, STATE_UNKNOWN), _("No data returned from command\n"));
 
 	for (i = 0; i < chld_out.lines; i++) {
-		if (subst_text && result != state[result] &&
-		    result >= 0 && result <= 4) {
+		if (subst_text && result >= 0 && result <= 4 && result != state[result])  {
 			/* Loop over each match found */
 			while ((sub = strstr (chld_out.line[i], state_text (result)))) {
 				/* Terminate the first part and skip over the string we'll substitute */
@@ -206,7 +205,7 @@ process_arguments (int argc, char **argv)
 }
 
 
-int
+void
 validate_arguments (char **command_line)
 {
 	if (command_line[0] == NULL)

+ 12 - 3
plugins/netutils.c

@@ -171,11 +171,12 @@ np_net_connect (const char *host_name, int port, int *sd, int proto)
 	char port_str[6], host[MAX_HOST_ADDRESS_LENGTH];
 	size_t len;
 	int socktype, result;
+	short is_socket = (host_name[0] == '/');
 
 	socktype = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
 
 	/* as long as it doesn't start with a '/', it's assumed a host or ip */
-	if(host_name[0] != '/'){
+	if (!is_socket){
 		memset (&hints, 0, sizeof (hints));
 		hints.ai_family = address_family;
 		hints.ai_protocol = proto;
@@ -255,7 +256,11 @@ np_net_connect (const char *host_name, int port, int *sd, int proto)
 		case STATE_OK:
 		case STATE_WARNING:  /* user wants WARN or OK on refusal, or... */
 		case STATE_CRITICAL: /* user did not set econn_refuse_state, or wanted critical */
-			printf ("%s\n", strerror(errno));
+			if (is_socket)
+				printf("connect to file socket %s: %s\n", host_name, strerror(errno));
+			else
+				printf("connect to address %s and port %d: %s\n",
+				       host_name, port, strerror(errno));
 			return STATE_CRITICAL;
 			break;
 		default: /* it's a logic error if we do not end up in STATE_(OK|WARNING|CRITICAL) */
@@ -264,7 +269,11 @@ np_net_connect (const char *host_name, int port, int *sd, int proto)
 		}
 	}
 	else {
-		printf ("%s\n", strerror(errno));
+		if (is_socket)
+			printf("connect to file socket %s: %s\n", host_name, strerror(errno));
+		else
+			printf("connect to address %s and port %d: %s\n",
+			       host_name, port, strerror(errno));
 		return STATE_CRITICAL;
 	}
 }

+ 2 - 2
plugins/netutils.h

@@ -40,8 +40,8 @@
 #ifdef HAVE_SYS_UN_H
 # include <sys/un.h>
 # ifndef UNIX_PATH_MAX
-   /* linux uses this, on sun it's hard-coded at 108 without a define */
-#  define UNIX_PATH_MAX 108
+   /* linux uses this, on sun it's hard-coded at 108 without a define, on BSD at 104 */
+#  define UNIX_PATH_MAX 104
 # endif /* UNIX_PATH_MAX */
 #endif /* HAVE_SYS_UN_H */
 

+ 1 - 1
plugins/runcmd.c

@@ -261,7 +261,7 @@ runcmd_timeout_alarm_handler (int signo)
 	size_t i;
 
 	if (signo == SIGALRM)
-		puts(_("CRITICAL - Plugin timed out while executing system call\n"));
+		puts(_("CRITICAL - Plugin timed out while executing system call"));
 
 	if(np_pids) for(i = 0; i < maxfd; i++) {
 		if(np_pids[i] != 0) kill(np_pids[i], SIGKILL);

+ 6 - 5
plugins/sslutils.c

@@ -86,10 +86,12 @@ int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int
 	if (cert && privkey) {
 		SSL_CTX_use_certificate_file(c, cert, SSL_FILETYPE_PEM);
 		SSL_CTX_use_PrivateKey_file(c, privkey, SSL_FILETYPE_PEM);
+#ifdef USE_OPENSSL
 		if (!SSL_CTX_check_private_key(c)) {
 			printf ("%s\n", _("CRITICAL - Private key does not seem to match certificate!\n"));
 			return STATE_CRITICAL;
 		}
+#endif
 	}
 #ifdef SSL_OP_NO_TICKET
 	SSL_CTX_set_options(c, SSL_OP_NO_TICKET);
@@ -151,7 +153,8 @@ int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit){
 	struct tm stamp;
 	float time_left;
 	int days_left;
-	char timestamp[17] = "";
+	char timestamp[50] = "";
+	time_t tm_t;
 
 	certificate=SSL_get_peer_certificate(s);
 	if (!certificate) {
@@ -209,10 +212,8 @@ int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit){
 
 	time_left = difftime(timegm(&stamp), time(NULL));
 	days_left = time_left / 86400;
-	snprintf
-		(timestamp, 17, "%02d/%02d/%04d %02d:%02d",
-		 stamp.tm_mon + 1,
-		 stamp.tm_mday, stamp.tm_year + 1900, stamp.tm_hour, stamp.tm_min);
+	tm_t = mktime (&stamp);
+	strftime(timestamp, 50, "%c", localtime(&tm_t));
 
 	if (days_left > 0 && days_left <= days_till_exp_warn) {
 		printf (_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", cn, days_left, timestamp);

+ 56 - 0
plugins/t/NPTest.cache.travis

@@ -0,0 +1,56 @@
+{
+  'MYSQL_LOGIN_DETAILS' => '-u root -d test',
+  'NP_ALLOW_SUDO' => 'yes',
+  'NP_DNS_SERVER' => '8.8.8.8',
+  'NP_GOOD_NTP_SERVICE' => '',
+  'NP_HOSTNAME_INVALID' => 'nosuchhost',
+  'NP_HOSTNAME_VALID' => 'monitoringplugins.org',
+  'NP_HOSTNAME_VALID_IP' => '130.133.8.40',
+  'NP_HOSTNAME_VALID_REVERSE' => 'orwell.monitoring-plugins.org.',
+  'NP_HOST_DHCP_RESPONSIVE' => '',
+  'NP_HOST_NONRESPONSIVE' => '10.0.0.1',
+  'NP_HOST_RESPONSIVE' => 'localhost',
+  'NP_HOST_SMB' => '',
+  'NP_HOST_SNMP' => '',
+  'NP_HOST_TCP_FTP' => '',
+  'NP_HOST_TCP_HPJD' => '',
+  'NP_HOST_HPJD_PORT_INVALID' => '161',
+  'NP_HOST_HPJD_PORT_VALID' => '',
+  'NP_HOST_TCP_HTTP' => 'localhost',
+  'NP_HOST_TCP_HTTP2' => 'labs.consol.de',
+  'NP_HOST_TCP_IMAP' => 'imap.web.de',
+  'NP_HOST_TCP_POP' => 'pop.web.de',
+  'NP_HOST_TCP_SMTP' => 'localhost',
+  'NP_HOST_TCP_SMTP_NOTLS' => '',
+  'NP_HOST_TCP_SMTP_TLS' => '',
+  'NP_INTERNET_ACCESS' => 'yes',
+  'NP_MOUNTPOINT2_VALID' => '',
+  'NP_MOUNTPOINT_VALID' => '/',
+  'NP_MYSQL_SERVER' => 'localhost',
+  'NP_HOST_UDP_TIME' => 'localhost',
+  'NP_MYSQL_SOCKET' => '/var/run/mysqld/mysqld.sock',
+  'NP_MYSQL_WITH_SLAVE' => '',
+  'NP_MYSQL_WITH_SLAVE_LOGIN' => '',
+  'NP_NO_NTP_SERVICE' => 'localhost',
+  'NP_SMB_SHARE' => '',
+  'NP_SMB_SHARE_DENY' => '',
+  'NP_SMB_SHARE_SPC' => '',
+  'NP_SMB_VALID_USER' => '',
+  'NP_SMB_VALID_USER_PASS' => '',
+  'NP_SNMP_COMMUNITY' => '',
+  'NP_SSH_CONFIGFILE' => '~/.ssh/config',
+  'NP_SSH_HOST' => 'localhost',
+  'NP_SSH_IDENTITY' => '~/.ssh/id_dsa',
+  'NP_HOST_TCP_JABBER' => 'jabber.org',
+  'host_nonresponsive' => '10.0.0.1',
+  'host_responsive' => 'localhost',
+  'host_snmp' => '',
+  'host_tcp_ftp' => '',
+  'host_tcp_http' => 'localhost',
+  'host_tcp_imap' => 'imap.nierlein.de',
+  'host_tcp_smtp' => 'localhost',
+  'hostname_invalid' => 'nosuchhost',
+  'snmp_community' => '',
+  'user_snmp' => '',
+  'host_udp_time' => 'none',
+}

+ 2 - 1
plugins/t/check_dns.t

@@ -10,7 +10,7 @@ use NPTest;
 
 plan skip_all => "check_dns not compiled" unless (-x "check_dns");
 
-plan tests => 13;
+plan tests => 14;
 
 my $successOutput = '/DNS OK: [\.0-9]+ seconds? response time/';
 
@@ -54,6 +54,7 @@ cmp_ok( $res->return_code, '==', 2, "Critical threshold passed");
 
 $res = NPTest->testCmd("./check_dns -H $hostname_valid -t 5 -w 0 -c 5");
 cmp_ok( $res->return_code, '==', 1, "Warning threshold passed");
+like( $res->output, '/\|time=[\d\.]+s;0.0*;5\.0*;0\.0*/', "Output performance data OK" );
 
 $res = NPTest->testCmd("./check_dns -H $hostname_invalid -t 1");
 cmp_ok( $res->return_code, '==', 2, "Invalid $hostname_invalid");

+ 8 - 6
plugins/t/check_fping.t

@@ -27,16 +27,18 @@ my $hostname_invalid   = getTestParameter( "hostname_invalid",   "NP_HOSTNAME_IN
 
 my $t;
 
-if ( -x "./check_fping" )
-{
+my $fping = qx(which fping 2> /dev/null);
+chomp($fping);
+if( ! -x "./check_fping") {
+  $t += skipMissingCmd( "./check_fping", $tests );
+}
+elsif ( $> != 0 && (!$fping || ! -u $fping)) {
+  $t += skipMsg( "./check_fping", $tests );
+} else {
   $t += checkCmd( "./check_fping $host_responsive",    0,       $successOutput );
   $t += checkCmd( "./check_fping $host_nonresponsive", [ 1, 2 ] );
   $t += checkCmd( "./check_fping $hostname_invalid",   [ 1, 2 ] );
 }
-else
-{
-  $t += skipMissingCmd( "./check_fping", $tests );
-}
 
 exit(0) if defined($Test::Harness::VERSION);
 exit($tests - $t);

+ 28 - 7
plugins/t/check_hpjd.t

@@ -10,7 +10,6 @@ use NPTest;
 
 plan skip_all => "check_hpjd not compiled" unless (-x "check_hpjd");
 
-plan tests => 5;
 
 my $successOutput = '/^Printer ok - /';
 my $failureOutput = '/Timeout: No [Rr]esponse from /';
@@ -20,31 +19,53 @@ my $host_tcp_hpjd = getTestParameter(
 			"A host (usually a printer) providing the HP-JetDirect Services"
 			);
 
+my $host_hpjd_port_invalid = getTestParameter( 
+			"NP_HOST_HPJD_PORT_INVALID",
+			"A port that HP-JetDirect Services is not listening on",
+			"162"
+			);
+
+my $host_hpjd_port_valid = getTestParameter( 
+			"NP_HOST_HPJD_PORT_VALID",
+			"The port that HP-JetDirect Services is currently listening on",
+			"161"
+			);
+
 my $host_nonresponsive = getTestParameter( 
 			"NP_HOST_NONRESPONSIVE",
 			"The hostname of system not responsive to network requests",
-			"10.0.0.1",
+			"10.0.0.1"
 			);
 
 my $hostname_invalid = getTestParameter( 
 			"NP_HOSTNAME_INVALID",
 			"An invalid (not known to DNS) hostname",
-			"nosuchhost",
+			"nosuchhost"
 			);
 
+my $tests = $host_tcp_hpjd ? 9 : 5;
+plan tests => $tests;
 my $res;
 
 SKIP: {
 	skip "No HP JetDirect defined", 2 unless $host_tcp_hpjd;
-	$res = NPTest->testCmd("./check_hpjd $host_tcp_hpjd");
-	cmp_ok( $res->return_code, '==', 0, "Jetdirect responding" );
+	$res = NPTest->testCmd("./check_hpjd -H $host_tcp_hpjd");
+	cmp_ok( $res->return_code, 'eq', 0, "Jetdirect responding" );
 	like  ( $res->output, $successOutput, "Output correct" );
+
+	$res = NPTest->testCmd("./check_hpjd -H $host_tcp_hpjd -p $host_hpjd_port_valid");
+	cmp_ok( $res->return_code, 'eq', 0, "Jetdirect responding on port $host_hpjd_port_valid" );
+	like  ( $res->output, $successOutput, "Output correct" );
+
+	$res = NPTest->testCmd("./check_hpjd -H $host_tcp_hpjd -p $host_hpjd_port_invalid");
+	cmp_ok( $res->return_code, 'eq', 2, "Jetdirect not responding on port $host_hpjd_port_invalid" );
+	like  ( $res->output, $failureOutput, "Output correct" );
 }
 
-$res = NPTest->testCmd("./check_hpjd $host_nonresponsive");
+$res = NPTest->testCmd("./check_hpjd -H $host_nonresponsive");
 cmp_ok( $res->return_code, 'eq', 2, "Host not responding");
 like  ( $res->output, $failureOutput, "Output OK" );
 
-$res = NPTest->testCmd("./check_hpjd $hostname_invalid");
+$res = NPTest->testCmd("./check_hpjd -H $hostname_invalid");
 cmp_ok( $res->return_code, 'eq', 3, "Hostname invalid");
 

+ 3 - 3
plugins/t/check_jabber.t

@@ -29,7 +29,7 @@ my $hostname_invalid   = getTestParameter(
 			);
 
 
-my $jabberOK = '/JABBER OK\s-\s\d+\.\d+\ssecond response time on port 5222/';
+my $jabberOK = '/JABBER OK\s-\s\d+\.\d+\ssecond response time on '.$host_tcp_jabber.' port 5222/';
 
 my $jabberUnresponsive = '/CRITICAL\s-\sSocket timeout after\s\d+\sseconds/';
 
@@ -40,7 +40,7 @@ my $r;
 SKIP: {
 	skip "No jabber server defined", 6 unless $host_tcp_jabber;
 
-	$r = NPTest->testCmd( "./check_jabber $host_tcp_jabber" );
+	$r = NPTest->testCmd( "./check_jabber -H $host_tcp_jabber" );
 	is( $r->return_code, 0, "Connected okay");
 	like( $r->output, $jabberOK, "Output as expected" );
 
@@ -48,7 +48,7 @@ SKIP: {
 	is( $r->return_code, 0, "Connected okay, within limits" );
 	like( $r->output, $jabberOK, "Output as expected" );
 	
-	$r = NPTest->testCmd( "./check_jabber $host_tcp_jabber -wt 9 -ct 9 -to 10" );
+	$r = NPTest->testCmd( "./check_jabber -H $host_tcp_jabber -wt 9 -ct 9 -to 10" );
 	is( $r->return_code, 0, "Old syntax okay" );
 	like( $r->output, $jabberOK, "Output as expected" );
 

+ 7 - 7
plugins/t/check_ntp.t

@@ -23,27 +23,27 @@ my $no_ntp_service = getTestParameter( "NP_NO_NTP_SERVICE",
 		"A host NOT providing the NTP service",
 		"localhost" );
 
-my $host_nonresponsive = getTestParameter( "NP_HOST_NONRESPONSIVE", 
+my $host_nonresponsive = getTestParameter( "NP_HOST_NONRESPONSIVE",
 		"The hostname of system not responsive to network requests",
 		"10.0.0.1" );
 
-my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID", 
-		"An invalid (not known to DNS) hostname",  
+my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID",
+		"An invalid (not known to DNS) hostname",
 		"nosuchhost");
 
 my $ntp_okmatch1 = '/^NTP\sOK:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs/';
 my $ntp_warnmatch1 = '/^NTP\sWARNING:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs/';
 my $ntp_critmatch1 = '/^NTP\sCRITICAL:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs/';
 my $ntp_okmatch2 = '/^NTP\sOK:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+,\sstratum=[0-9]{1,2},\struechimers=[0-9]+/';
-my $ntp_warnmatch2 = '/^NTP\sWARNING:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+,\sstratum=[0-9]{1,2},\struechimers=[0-9]+/';
-my $ntp_critmatch2 = '/^NTP\sCRITICAL:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+,\sstratum=[0-9]{1,2},\struechimers=[0-9]+/';
+my $ntp_warnmatch2 = '/^NTP\sWARNING:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+,\sstratum=[0-9]{1,2}\s\(WARNING\),\struechimers=[0-9]+/';
+my $ntp_critmatch2 = '/^NTP\sCRITICAL:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+\s\(CRITICAL\),\sstratum=[0-9]{1,2},\struechimers=[0-9]+/';
 my $ntp_noresponse = '/^(CRITICAL - Socket timeout after 3 seconds)|(NTP CRITICAL: No response from NTP server)$/';
 my $ntp_nosuchhost = '/^check_ntp.*: Invalid hostname/address - ' . $hostname_invalid . '/';
 
 
 foreach my $plugin (@PLUGINS1) {
 	SKIP: {
-		skip "No NTP server defined", 1 unless $ntp_service;
+		skip "No NTP server defined", 6 unless $ntp_service;
 		$res = NPTest->testCmd(
 			"./$plugin -H $ntp_service -w 1000 -c 2000"
 			);
@@ -88,7 +88,7 @@ foreach my $plugin (@PLUGINS1) {
 
 foreach my $plugin (@PLUGINS2) {
 	SKIP: {
-		skip "No NTP server defined", 1 unless $ntp_service;
+		skip "No NTP server defined", 6 unless $ntp_service;
 		$res = NPTest->testCmd(
 			"./$plugin -H $ntp_service -w 1000 -c 2000 -W 20 -C 21 -j 100000 -k 200000 -m 1: -n 0:"
 			);

+ 1 - 1
plugins/t/check_procs.t

@@ -26,7 +26,7 @@ $result = NPTest->testCmd( "./check_procs -w 100000 -c 100000 -s Z" );
 is( $result->return_code, 0, "Checking less than 100000 zombie processes" );
 like( $result->output, '/^PROCS OK: [0-9]+ process(es)? with /', "Output correct" );
 
-if(fork() == 0) { exec("sleep 7"); } # fork a test process
+if(fork() == 0) { exec("sleep 7"); } else { sleep(1) } # fork a test process in child and give child time to fork in parent
 $result = NPTest->testCmd( "./check_procs -a 'sleep 7'" );
 is( $result->return_code, 0, "Parent process is ignored" );
 like( $result->output, '/^PROCS OK: 1 process?/', "Output correct" );

+ 1 - 1
plugins/t/check_snmp.t

@@ -45,7 +45,7 @@ is( $res->return_code, 3, "Invalid protocol" );
 like( $res->output, "/check_snmp: Invalid SNMP version - 3c/" );
 
 SKIP: {
-    skip "no snmp host defined", 38 if ( ! $host_snmp );
+    skip "no snmp host defined", 48 if ( ! $host_snmp );
 
     $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o system.sysUpTime.0 -w 1: -c 1:");
     cmp_ok( $res->return_code, '==', 0, "Exit OK when querying uptime" );

+ 1 - 1
plugins/t/check_udp.t

@@ -62,7 +62,7 @@ SKIP: {
 	cmp_ok( $res->return_code, '==', '2', "Hung waiting for response");
 	like  ( $res->output, '/Socket timeout after 5 seconds/', "Timeout message");
 	like  ( $duration, '/^[56]$/', "Timeout after 5 (possibly 6) seconds");
-	my $read_nc = <NC>;
+	my $read_nc = <NC> || '';
 	close NC;
 	cmp_ok( $read_nc, 'eq', "foofoo", "Data received correctly" );
 }

+ 15 - 20
plugins/tests/check_http.t

@@ -20,8 +20,9 @@ use FindBin qw($Bin);
 my $common_tests = 70;
 my $ssl_only_tests = 8;
 # Check that all dependent modules are available
+eval "use HTTP::Daemon 6.01;";
+plan skip_all => 'HTTP::Daemon >= 6.01 required' if $@;
 eval {
-	require HTTP::Daemon;
 	require HTTP::Status;
 	require HTTP::Response;
 };
@@ -185,21 +186,21 @@ SKIP: {
 
 	$result = NPTest->testCmd( "$command -p $port_https -S -C 14" );
 	is( $result->return_code, 0, "$command -p $port_https -S -C 14" );
-	is( $result->output, 'OK - Certificate \'Ton Voon\' will expire on 03/03/2019 21:41.', "output ok" );
+	is( $result->output, 'OK - Certificate \'Ton Voon\' will expire on Sun Mar  3 21:41:00 2019.', "output ok" );
 
 	$result = NPTest->testCmd( "$command -p $port_https -S -C 14000" );
 	is( $result->return_code, 1, "$command -p $port_https -S -C 14000" );
-	like( $result->output, '/WARNING - Certificate \'Ton Voon\' expires in \d+ day\(s\) \(03/03/2019 21:41\)./', "output ok" );
+	like( $result->output, '/WARNING - Certificate \'Ton Voon\' expires in \d+ day\(s\) \(Sun Mar  3 21:41:00 2019\)./', "output ok" );
 
 	# Expired cert tests
 	$result = NPTest->testCmd( "$command -p $port_https -S -C 13960,14000" );
 	is( $result->return_code, 2, "$command -p $port_https -S -C 13960,14000" );
-	like( $result->output, '/CRITICAL - Certificate \'Ton Voon\' expires in \d+ day\(s\) \(03/03/2019 21:41\)./', "output ok" );
+	like( $result->output, '/CRITICAL - Certificate \'Ton Voon\' expires in \d+ day\(s\) \(Sun Mar  3 21:41:00 2019\)./', "output ok" );
 
 	$result = NPTest->testCmd( "$command -p $port_https_expired -S -C 7" );
 	is( $result->return_code, 2, "$command -p $port_https_expired -S -C 7" );
 	is( $result->output,
-		'CRITICAL - Certificate \'Ton Voon\' expired on 03/05/2009 00:13.',
+		'CRITICAL - Certificate \'Ton Voon\' expired on Thu Mar  5 00:13:00 2009.',
 		"output ok" );
 
 }
@@ -392,27 +393,21 @@ sub run_common_tests {
 		skip "This doesn't seems to work all the time", 1 unless ($ENV{HTTP_EXTERNAL});
 		$cmd = "$command -f follow -u /redir_external -t 5";
 		eval {
-			local $SIG{ALRM} = sub { die "alarm\n" };
-			alarm(2);
-			$result = NPTest->testCmd( $cmd );
-			alarm(0); };
-		is( $@, "alarm\n", $cmd );
+			$result = NPTest->testCmd( $cmd, 2 );
+		};
+		like( $@, "/timeout in command: $cmd/", $cmd );
 	}
 
 	$cmd = "$command -u /timeout -t 5";
 	eval {
-		local $SIG{ALRM} = sub { die "alarm\n" };
-		alarm(2);
-		$result = NPTest->testCmd( $cmd );
-		alarm(0); };
-	is( $@, "alarm\n", $cmd );
+		$result = NPTest->testCmd( $cmd, 2 );
+	};
+	like( $@, "/timeout in command: $cmd/", $cmd );
 
 	$cmd = "$command -f follow -u /redir_timeout -t 2";
 	eval {
-		local $SIG{ALRM} = sub { die "alarm\n" };
-		alarm(5);
-		$result = NPTest->testCmd( $cmd );
-		alarm(0); };
-	isnt( $@, "alarm\n", $cmd );
+		$result = NPTest->testCmd( $cmd, 5 );
+	};
+	is( $@, "", $cmd );
 
 }

+ 17 - 12
plugins/tests/check_procs.t

@@ -48,21 +48,26 @@ SKIP: {
     like( $result->output, '/^PROCS OK: 1 process with command name \'launchd\', UID = 501 (.*)$/', "Output correct" );
 }
 
-$result = NPTest->testCmd( "$command -u -2 -w 2:2" );
-is( $result->return_code, 1, "Checking processes with userid=-2" );
-like( $result->output, '/^PROCS WARNING: 3 processes with UID = -2 \(nobody\)$/', "Output correct" );
+SKIP: {
+    skip 'user with uid -2 required', 8 unless getpwuid(-2);
+    skip 'uid -2 must have name "nobody"', 8 unless getpwuid(-2) eq 'nobody';
+
+    $result = NPTest->testCmd( "$command -u -2 -w 2:2" );
+    is( $result->return_code, 1, "Checking processes with userid=-2" );
+    like( $result->output, '/^PROCS WARNING: 3 processes with UID = -2 \(nobody\)$/', "Output correct" );
 
-$result = NPTest->testCmd( "$command -u -2 -w 3:3" );
-is( $result->return_code, 0, "Checking processes with userid=-2 past threshold" );
-like( $result->output, '/^PROCS OK: 3 processes with UID = -2 \(nobody\)$/', "Output correct" );
+    $result = NPTest->testCmd( "$command -u -2 -w 3:3" );
+    is( $result->return_code, 0, "Checking processes with userid=-2 past threshold" );
+    like( $result->output, '/^PROCS OK: 3 processes with UID = -2 \(nobody\)$/', "Output correct" );
 
-$result = NPTest->testCmd( "$command -u -2 -a usb" );
-is( $result->return_code, 0, "Checking processes with userid=-2 and usb in arguments" );
-like( $result->output, '/^PROCS OK: 1 process with UID = -2 \(nobody\), args \'usb\'/', "Output correct" );
+    $result = NPTest->testCmd( "$command -u -2 -a usb" );
+    is( $result->return_code, 0, "Checking processes with userid=-2 and usb in arguments" );
+    like( $result->output, '/^PROCS OK: 1 process with UID = -2 \(nobody\), args \'usb\'/', "Output correct" );
 
-$result = NPTest->testCmd( "$command -u -2 -a UsB" );
-is( $result->return_code, 0, "Checking case sensitivity of args" );
-like( $result->output, '/^PROCS OK: 0 processes with UID = -2 \(nobody\), args \'UsB\'/', "Output correct" );
+    $result = NPTest->testCmd( "$command -u -2 -a UsB" );
+    is( $result->return_code, 0, "Checking case sensitivity of args" );
+    like( $result->output, '/^PROCS OK: 0 processes with UID = -2 \(nobody\), args \'UsB\'/', "Output correct" );
+};
 
 $result = NPTest->testCmd( "$command --ereg-argument-array='mdworker.*501'" );
 is( $result->return_code, 0, "Checking regexp search of arguments" );

+ 1 - 1
plugins/tests/check_snmp.t

@@ -79,7 +79,7 @@ Copyright (c) 1986-2004 by cisco Systems, Inc.
 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.0 -o sysContact.0 -o .1.3.6.1.4.1.8072.3.2.67.1");
 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying multi-line OIDs" );
 like($res->output, '/^SNMP OK - /', "String contains SNMP OK");
-like($res->output, '/'.quotemeta('SNMP OK - Cisco Internetwork Operating System Software "Alice" Kisco Outernetwork Oserating Gystem Totware | 
+like($res->output, '/'.quotemeta('SNMP OK - Cisco Internetwork Operating System Software ').'"?Alice"?'.quotemeta(' Kisco Outernetwork Oserating Gystem Totware | 
 .1.3.6.1.4.1.8072.3.2.67.0:
 "Cisco Internetwork Operating System Software
 IOS (tm) Catalyst 4000 \"L3\" Switch Software (cat4000-I9K91S-M), Version

+ 2 - 2
po/de.po

@@ -1998,7 +1998,7 @@ msgstr ""
 
 #: plugins/check_mrtg.c:359
 msgid ""
-"packets/sec, etc.  I use MRTG in conjuction with the Novell NLM that allows"
+"packets/sec, etc.  I use MRTG in conjunction with the Novell NLM that allows"
 msgstr ""
 
 #: plugins/check_mrtg.c:360
@@ -5360,7 +5360,7 @@ msgstr ""
 
 #: plugins/check_ide_smart.c:441
 #, c-format
-msgid "ERROR - Status '%d' unkown. %d/%d tests passed\n"
+msgid "ERROR - Status '%d' unknown. %d/%d tests passed\n"
 msgstr ""
 
 #: plugins/check_ide_smart.c:474

+ 2 - 2
po/fr.po

@@ -2050,7 +2050,7 @@ msgstr ""
 
 #: plugins/check_mrtg.c:359
 msgid ""
-"packets/sec, etc.  I use MRTG in conjuction with the Novell NLM that allows"
+"packets/sec, etc.  I use MRTG in conjunction with the Novell NLM that allows"
 msgstr ""
 
 #: plugins/check_mrtg.c:360
@@ -5448,7 +5448,7 @@ msgstr "OK - En fonctionnement (%d/%d les tests on été réussi)\n"
 
 #: plugins/check_ide_smart.c:441
 #, c-format
-msgid "ERROR - Status '%d' unkown. %d/%d tests passed\n"
+msgid "ERROR - Status '%d' unknown. %d/%d tests passed\n"
 msgstr "ERREUR - État '%d' inconnu. %d/%d les tests on réussi\n"
 
 #: plugins/check_ide_smart.c:474

+ 2 - 2
po/monitoring-plugins.pot

@@ -1944,7 +1944,7 @@ msgstr ""
 
 #: plugins/check_mrtg.c:359
 msgid ""
-"packets/sec, etc.  I use MRTG in conjuction with the Novell NLM that allows"
+"packets/sec, etc.  I use MRTG in conjunction with the Novell NLM that allows"
 msgstr ""
 
 #: plugins/check_mrtg.c:360
@@ -5217,7 +5217,7 @@ msgstr ""
 
 #: plugins/check_ide_smart.c:441
 #, c-format
-msgid "ERROR - Status '%d' unkown. %d/%d tests passed\n"
+msgid "ERROR - Status '%d' unknown. %d/%d tests passed\n"
 msgstr ""
 
 #: plugins/check_ide_smart.c:474

+ 2 - 0
test.pl.in

@@ -9,6 +9,8 @@ use Getopt::Long;
 
 use NPTest qw(DetermineTestHarnessDirectory TestsFrom);
 
+$ENV{LC_ALL} = 'C';
+
 my @tstdir;
 
 if ( ! GetOptions( "testdir:s" => \@tstdir ) )