[nagios-plugins] check_ssh using libssh to verify host ...

Git Repository git at nagios-plugins.org
Fri Oct 4 00:10:06 CEST 2013


    Module: nagios-plugins
    Branch: pu
    Commit: 776f03beaad1595502c3ccbf5532568e64c90c9d
    Author: hjanuschka <helmut at januschka.com>
 Committer: Thomas Guyot-Sionnest <dermoth at aei.ca>
      Date: Tue Dec  4 13:29:40 2012 +0100
       URL: https://www.nagios-plugins.org/repositories/nagios-plugins.git/?/commit/?id=776f03b

     check_ssh using libssh to verify host fingerprint and openssh version

    if libssh is not found, the fingerprint / openssh-version-detection functions are not compiled in.
    for backward compatibility the parameters of original check_ssh stay untouched
    for checking the fingerprint && || the openssh version use -f and or -o

    to check against known_hosts file use -f known_host

    sample calls:
        #checks if SSH fingerprint is stored in local known hosts
        ./check_ssh -f known_hosts  localhost

        #checks if SSH fingerprint is stored in local known hosts, and version is >= 5.5
        ./check_ssh -f known_hosts  -o 5.5 localhost

        #checks if SSH fingerprint is equal the print supplied with -f
        ./check_ssh -f  a2:47:e8:83:d9:8b:f5:c4:19:23:47:0d:e0:bf:a8:26  localhost

        #checks if SSH fingerprint is equal the print supplied with -f and version is >= 5.5
        ./check_ssh -f  a2:47:e8:83:d9:8b:f5:c4:19:23:47:0d:e0:bf:a8:26  -o 5.5 localhost

        #check for SSH version
        ./check_ssh -o 5.5 localhost

---

 configure.in        |   14 ++++
 plugins/Makefile.am |    2 +-
 plugins/check_ssh.c |  206 ++++++++++++++++++++++++++++++++++++++-------------
 3 files changed, 170 insertions(+), 52 deletions(-)

diff --git a/configure.in b/configure.in
index 1d4ed00..a951d39 100644
--- a/configure.in
+++ b/configure.in
@@ -204,6 +204,20 @@ if test "$enable_extra_opts" = "yes" ; then
 	fi
 fi
 
+
+dnl Check for ssh libraries
+
+AC_CHECK_LIB(ssh,ssh_connect)
+if test "$ac_cv_lib_ssh_ssh_connect" = "yes"; then
+	SSHLIB="-lssh"
+  AC_SUBST(SSHLIB)
+  AC_DEFINE(HAVE_SSH,1,[Define if SSL libraries are found])
+else
+    AC_MSG_WARN([Skipping check_ssh plugin])
+    AC_MSG_WARN([install ssh libs to compile this plugin (see REQUIREMENTS).])
+fi
+
+
 dnl Check for PostgreSQL libraries
 _SAVEDLIBS="$LIBS"
 _SAVEDCPPFLAGS="$CPPFLAGS"
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 0eb0255..7cea40c 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -96,7 +96,7 @@ check_radius_LDADD = $(NETLIBS) $(RADIUSLIBS)
 check_real_LDADD = $(NETLIBS)
 check_snmp_LDADD = $(BASEOBJS)
 check_smtp_LDADD = $(SSLOBJS) $(NETLIBS) $(SSLLIBS)
-check_ssh_LDADD = $(NETLIBS)
+check_ssh_LDADD = $(NETLIBS) $(SSHLIB)
 check_swap_LDADD = $(MATHLIBS) $(BASEOBJS) popen.o
 check_tcp_LDADD = $(SSLOBJS) $(NETLIBS) $(SSLLIBS)
 check_time_LDADD = $(NETLIBS)
diff --git a/plugins/check_ssh.c b/plugins/check_ssh.c
index 6e8a5fc..c3526c9 100644
--- a/plugins/check_ssh.c
+++ b/plugins/check_ssh.c
@@ -36,6 +36,10 @@ const char *email = "nagiosplug-devel at lists.sourceforge.net";
 #include "netutils.h"
 #include "utils.h"
 
+#ifdef HAVE_SSH
+#include <libssh/libssh.h>
+#endif
+
 #ifndef MSG_DONTWAIT
 #define MSG_DONTWAIT 0
 #endif
@@ -46,15 +50,17 @@ const char *email = "nagiosplug-devel at lists.sourceforge.net";
 int port = -1;
 char *server_name = NULL;
 char *remote_version = NULL;
+char *remote_fingerprint = NULL;
 int verbose = FALSE;
+char * remote_openssh_version = NULL;
 
 int process_arguments (int, char **);
 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_p (char *haddr, int hport, char *remote_version, char *remote_fingerprint);
+int ssh_connect_wo_lib (char *haddr, int hport, char *remote_version);
 
 
 int
@@ -78,14 +84,80 @@ main (int argc, char **argv)
 	alarm (socket_timeout);
 
 	/* ssh_connect exits if error is found */
-	result = ssh_connect (server_name, port, remote_version);
 
+	#ifdef HAVE_SSH
+	if(remote_openssh_version != NULL || remote_fingerprint != NULL) {
+		result = ssh_connect_p (server_name, port, remote_openssh_version, remote_fingerprint);
+	} else {
+		result = ssh_connect_wo_lib(server_name, port, remote_version);
+	}
+	#else
+	result = ssh_connect_wo_lib(server_name, port, remote_version);
+	#endif
 	alarm (0);
 
 	return (result);
 }
 
+int
+ssh_connect_wo_lib (char *haddr, int hport, char *remote_version)
+{
+	int sd;
+	int result;
+	char *output = NULL;
+	char *buffer = NULL;
+	char *ssh_proto = NULL;
+	char *ssh_server = NULL;
+	static char *rev_no = VERSION;
+	struct timeval tv;
+	double elapsed_time;
 
+	gettimeofday(&tv, NULL);
+
+	result = my_tcp_connect (haddr, hport, &sd);
+
+	if (result != STATE_OK)
+		return result;
+
+	output = (char *) malloc (BUFF_SZ + 1);
+	memset (output, 0, BUFF_SZ + 1);
+	recv (sd, output, BUFF_SZ, 0);
+	if (strncmp (output, "SSH", 3)) {
+		printf (_("Server answer: %s"), output);
+		close(sd);
+		exit (STATE_CRITICAL);
+	}
+	else {
+		strip (output);
+		if (verbose)
+			printf ("%s\n", output);
+		ssh_proto = output + 4;
+		ssh_server = ssh_proto + strspn (ssh_proto, "-0123456789. ");
+		ssh_proto[strspn (ssh_proto, "0123456789. ")] = 0;
+
+		xasprintf (&buffer, "SSH-%s-check_ssh_%s\r\n", ssh_proto, rev_no);
+		send (sd, buffer, strlen (buffer), MSG_DONTWAIT);
+		if (verbose)
+			printf ("%s\n", buffer);
+
+		if (remote_version && strcmp(remote_version, ssh_server)) {
+			printf
+				(_("SSH WARNING - %s (protocol %s) version mismatch, expected '%s'\n"),
+				 ssh_server, ssh_proto, remote_version);
+			close(sd);
+			exit (STATE_WARNING);
+		}
+
+		elapsed_time = (double)deltime(tv) / 1.0e6;
+
+		printf
+			(_("SSH OK - %s (protocol %s) | %s\n"),
+			 ssh_server, ssh_proto, fperfdata("time", elapsed_time, "s",
+			 FALSE, 0, FALSE, 0, TRUE, 0, TRUE, (int)socket_timeout));
+		close(sd);
+		exit (STATE_OK);
+	}
+}
 
 /* process command-line arguments */
 int
@@ -105,6 +177,8 @@ process_arguments (int argc, char **argv)
 		{"timeout", required_argument, 0, 't'},
 		{"verbose", no_argument, 0, 'v'},
 		{"remote-version", required_argument, 0, 'r'},
+		{"fingerprint", required_argument, 0, 'f'},
+		{"remote-openssh-version", required_argument, 0, 'o'},
 		{0, 0, 0, 0}
 	};
 
@@ -116,7 +190,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:f:H:o:p:", longopts, &option);
 
 		if (c == -1 || c == EOF)
 			break;
@@ -152,6 +226,12 @@ process_arguments (int argc, char **argv)
 		case 'r':									/* remote version */
 			remote_version = optarg;
 			break;
+		case 'o':
+			remote_openssh_version = optarg;
+		break;
+		case 'f':									/* remote version */
+			remote_fingerprint = optarg;
+			break;
 		case 'H':									/* host */
 			if (is_host (optarg) == FALSE)
 				usage2 (_("Invalid hostname/address"), optarg);
@@ -204,66 +284,82 @@ validate_arguments (void)
 *
 *-----------------------------------------------------------------------*/
 
-
+#ifdef HAVE_SSH
 int
-ssh_connect (char *haddr, int hport, char *remote_version)
+ssh_connect_p (char *haddr, int hport, char *remote_version, char * remote_fingerprint)
 {
-	int sd;
-	int result;
-	char *output = NULL;
-	char *buffer = NULL;
-	char *ssh_proto = NULL;
-	char *ssh_server = NULL;
-	static char *rev_no = VERSION;
 	struct timeval tv;
 	double elapsed_time;
 
+	ssh_session my_ssh_session;
+	int  version;
+	int myversion;
+	int hlen;
+	int rc;
+	int state;
+	int i;
+	unsigned char *hash = NULL;
+	char *  fingerprint;
+	int in_known_host;
+
+	int sshv1,sshv2,sshv3;
+
 	gettimeofday(&tv, NULL);
 
-	result = my_tcp_connect (haddr, hport, &sd);
+	my_ssh_session = ssh_new();
 
-	if (result != STATE_OK)
-		return result;
+	if (my_ssh_session == NULL)
+		return STATE_CRITICAL;
 
-	output = (char *) malloc (BUFF_SZ + 1);
-	memset (output, 0, BUFF_SZ + 1);
-	recv (sd, output, BUFF_SZ, 0);
-	if (strncmp (output, "SSH", 3)) {
-		printf (_("Server answer: %s"), output);
-		close(sd);
+	ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, haddr);
+	ssh_options_set(my_ssh_session, SSH_OPTIONS_PORT, &hport);
+	rc = ssh_connect(my_ssh_session);
+	if (rc != SSH_OK) {
+		printf ("Connect to Server failed\n");
 		exit (STATE_CRITICAL);
 	}
-	else {
-		strip (output);
-		if (verbose)
-			printf ("%s\n", output);
-		ssh_proto = output + 4;
-		ssh_server = ssh_proto + strspn (ssh_proto, "-0123456789. ");
-		ssh_proto[strspn (ssh_proto, "0123456789. ")] = 0;
+	in_known_host=-1;
+	state = ssh_is_server_known(my_ssh_session);
+	hlen = ssh_get_pubkey_hash(my_ssh_session, &hash);
+
+	/* Get the finger print as a string */
+	fingerprint = ssh_get_hexa(hash, hlen);
+	if(remote_fingerprint && strcmp(remote_fingerprint, "known_host") == NULL) {
+		if(state != SSH_SERVER_KNOWN_OK) {
+			printf ("SSH CRITICAL - Fingerprint (%s) checked in known_hosts failed\n", remote_fingerprint,fingerprint);
+			exit(STATE_CRITICAL);
+		} else {
+			in_known_host=1;
+		}
+	}
 
-		xasprintf (&buffer, "SSH-%s-check_ssh_%s\r\n", ssh_proto, rev_no);
-		send (sd, buffer, strlen (buffer), MSG_DONTWAIT);
-		if (verbose)
-			printf ("%s\n", buffer);
+	/* FIXME: This alwats eval to false... */
+	if(remote_fingerprint && strcmp(remote_fingerprint, "known_host") && strcmp(remote_fingerprint, fingerprint)) {
+		printf ("SSH CRITICAL - Fingerprint (%s) mismatched %s\n", remote_fingerprint,fingerprint);
+		free(fingerprint);
+		exit(STATE_CRITICAL);
+	}
 
-		if (remote_version && strcmp(remote_version, ssh_server)) {
-			printf
-				(_("SSH WARNING - %s (protocol %s) version mismatch, expected '%s'\n"),
-				 ssh_server, ssh_proto, remote_version);
-			close(sd);
-			exit (STATE_WARNING);
+	version = ssh_get_openssh_version(my_ssh_session);
+	if(remote_version && sscanf(remote_version, "%d.%d.%d", &sshv1, &sshv2, &sshv3)) {
+		myversion = SSH_VERSION_INT(sshv1, sshv2, sshv3);
+		if(version < myversion) {
+			printf ("SSH WARNING version on server is below %s\n", remote_version);
+			exit(STATE_CRITICAL);
 		}
+	}
 
-		elapsed_time = (double)deltime(tv) / 1.0e6;
+	elapsed_time = (double)deltime(tv) / 1.0e6;
 
-		printf
-			(_("SSH OK - %s (protocol %s) | %s\n"),
-			 ssh_server, ssh_proto, fperfdata("time", elapsed_time, "s",
-			 FALSE, 0, FALSE, 0, TRUE, 0, TRUE, (int)socket_timeout));
-		close(sd);
-		exit (STATE_OK);
-	}
+	printf (_("SSH OK - fingerprint: %s (Version %d) known_host_check:%d | %s\n"),
+	        fingerprint, version,in_known_host, fperfdata("time", elapsed_time, "s",
+	        FALSE, 0, FALSE, 0, TRUE, 0, TRUE, (int)socket_timeout));
+	free(fingerprint);
+	ssh_disconnect(my_ssh_session);
+	ssh_free(my_ssh_session);
+	exit(STATE_OK);
 }
+#endif
 
 
 
@@ -280,7 +376,7 @@ print_help (void)
 
 	printf ("%s\n", _("Try to connect to an SSH server at specified server and port"));
 
-  printf ("\n\n");
+	printf ("\n\n");
 
 	print_usage ();
 
@@ -294,7 +390,15 @@ print_help (void)
 	printf (UT_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
 
 	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", _("Warn if string doesn't match expected server version (ex: OpenSSH_3.9p1)"));
+
+#ifdef HAVE_SSH
+	printf (" %s\n", "-o, --remote-openssh-version=STRING");
+	printf ("    %s\n", _("Warn if Remote Openssh version is lower than STRING"));
+#endif
+
+	printf (" %s\n", "-f, --fingerprint=STRING (e.g.: a247e883d98bf5c41923470de0bfa826)");
+	printf ("    %s\n", _("Critical if remote fingerprint is not equal to supplied"));
 
 	printf (UT_VERBOSE);
 
@@ -306,7 +410,7 @@ print_help (void)
 void
 print_usage (void)
 {
-  printf ("%s\n", _("Usage:"));
-	printf ("%s  [-4|-6] [-t <timeout>] [-r <remote version>] [-p <port>] <host>\n", progname);
+	printf ("%s\n", _("Usage:"));
+	printf ("%s  [-4|-6] [-t <timeout>] [-f <fingerprint>] [-r <remote version>] [-o <remote openssh version>] [-p <port>] <host>\n", progname);
 }
 





More information about the Commits mailing list