[nagiosplug] added support for client authentication via SSL

Nagios Plugin Development nagios-plugins at users.sourceforge.net
Sun Aug 18 23:20:30 CEST 2013


 Module: nagiosplug
 Branch: master
 Commit: 2f92d0dab77a3f3b1005dae3401ea1316d6789b2
 Author: Lionel Cons <lionel.cons at cern.ch>
   Date: Fri May 17 15:00:09 2013 +0200
    URL: http://nagiosplug.git.sf.net/git/gitweb.cgi?p=nagiosplug/nagiosplug;a=commit;h=2f92d0d

added support for client authentication via SSL

---

 plugins/check_http.c |   45 ++++++++++++++++++++++++++++++++++++++++-----
 plugins/netutils.h   |    2 ++
 plugins/sslutils.c   |   12 ++++++++++++
 3 files changed, 54 insertions(+), 5 deletions(-)

diff --git a/plugins/check_http.c b/plugins/check_http.c
index 9231a55..ddaca33 100644
--- a/plugins/check_http.c
+++ b/plugins/check_http.c
@@ -124,6 +124,8 @@ char *http_method;
 char *http_post_data;
 char *http_content_type;
 char buffer[MAX_INPUT_BUFFER];
+char *client_cert = NULL;
+char *client_privkey = NULL;
 
 int process_arguments (int, char **);
 int check_http (void);
@@ -170,7 +172,14 @@ main (int argc, char **argv)
   return result;
 }
 
-
+/* check whether a file exists */
+void
+test_file (char *path)
+{
+  if (access(path, R_OK) == 0)
+    return;
+  usage2 (_("file does not exist or is not readable"), path);
+}
 
 /* process command-line arguments */
 int
@@ -207,6 +216,8 @@ process_arguments (int argc, char **argv)
     {"linespan", no_argument, 0, 'l'},
     {"onredirect", required_argument, 0, 'f'},
     {"certificate", required_argument, 0, 'C'},
+    {"client-cert", required_argument, 0, 'E'},
+    {"private-key", required_argument, 0, 'K'},
     {"useragent", required_argument, 0, 'A'},
     {"header", required_argument, 0, 'k'},
     {"no-body", no_argument, 0, 'N'},
@@ -236,7 +247,7 @@ process_arguments (int argc, char **argv)
   }
 
   while (1) {
-    c = getopt_long (argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:e:p:s:R:r:u:f:C:nlLS::m:M:N", longopts, &option);
+    c = getopt_long (argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:e:p:s:R:r:u:f:C:E:K:nlLS::m:M:N", longopts, &option);
     if (c == -1 || c == EOF)
       break;
 
@@ -301,10 +312,23 @@ process_arguments (int argc, char **argv)
         days_till_exp_warn = atoi (optarg);
       }
       check_cert = TRUE;
-      /* Fall through to -S option */
+      goto enable_ssl;
+#endif
+    case 'E': /* use client certificate */
+#ifdef HAVE_SSL
+      test_file(optarg);
+      client_cert = optarg;
+      goto enable_ssl;
+#endif
+    case 'K': /* use client private key */
+#ifdef HAVE_SSL
+      test_file(optarg);
+      client_privkey = optarg;
+      goto enable_ssl;
 #endif
     case 'S': /* use SSL */
 #ifdef HAVE_SSL
+    enable_ssl:
       use_ssl = TRUE;
       if (optarg == NULL || c != 'S')
         ssl_version = 0;
@@ -316,6 +340,7 @@ process_arguments (int argc, char **argv)
       if (specify_port == FALSE)
         server_port = HTTPS_PORT;
 #else
+      /* -C -E and -K fall through to here without SSL */
       usage4 (_("Invalid option - SSL is not available"));
 #endif
       break;
@@ -497,6 +522,9 @@ process_arguments (int argc, char **argv)
   if (http_method == NULL)
     http_method = strdup ("GET");
 
+  if (client_cert && !client_privkey) 
+    usage4 (_("If you use a client certificate you must also specify a private key file"));
+
   return TRUE;
 }
 
@@ -820,7 +848,7 @@ check_http (void)
     die (STATE_CRITICAL, _("HTTP CRITICAL - Unable to open TCP socket\n"));
 #ifdef HAVE_SSL
   if (use_ssl == TRUE) {
-    result = np_net_ssl_init_with_hostname_and_version(sd, (use_sni ? host_name : NULL), ssl_version);
+    result = np_net_ssl_init_with_hostname_version_and_certificate(sd, (use_sni ? host_name : NULL), ssl_version, client_cert, client_privkey);
     if (result != STATE_OK)
       return result;
     if (check_cert == TRUE) {
@@ -1354,7 +1382,13 @@ print_help (void)
   printf ("    %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
   printf (" %s\n", "-C, --certificate=INTEGER[,INTEGER]");
   printf ("    %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
-  printf ("    %s\n", _("(when this option is used the URL is not checked.)\n"));
+  printf ("    %s\n", _("(when this option is used the URL is not checked.)"));
+  printf (" %s\n", "-E, --client-cert=FILE");
+  printf ("   %s\n", _("Name of file that contains the client certificate (PEM format)"));
+  printf ("   %s\n", _("to be used in establishing the SSL session"));
+  printf (" %s\n", "-K, --private-key=FILE");
+  printf ("   %s\n", _("Name of file containing the private key (PEM format)"));
+  printf ("   %s\n", _("matching the client certificate"));
 #endif
 
   printf (" %s\n", "-e, --expect=STRING");
@@ -1461,6 +1495,7 @@ print_usage (void)
 {
   printf ("%s\n", _("Usage:"));
   printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
+  printf ("       [-E <client certificate file>] [-K <private key>]\n");
   printf ("       [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-a auth]\n");
   printf ("       [-b proxy_auth] [-f <ok|warning|critcal|follow|sticky|stickyport>]\n");
   printf ("       [-e <expect>] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n");
diff --git a/plugins/netutils.h b/plugins/netutils.h
index 21017f1..765b3d5 100644
--- a/plugins/netutils.h
+++ b/plugins/netutils.h
@@ -100,6 +100,8 @@ extern int address_family;
 /* maybe this could be merged with the above np_net_connect, via some flags */
 int np_net_ssl_init(int sd);
 int np_net_ssl_init_with_hostname(int sd, char *host_name);
+int np_net_ssl_init_with_hostname_and_version(int sd, char *host_name, int version);
+int np_net_ssl_init_with_hostname_version_and_certificate(int sd, char *host_name, int version, char *cert, char *privkey);
 void np_net_ssl_cleanup();
 int np_net_ssl_write(const void *buf, int num);
 int np_net_ssl_read(void *buf, int num);
diff --git a/plugins/sslutils.c b/plugins/sslutils.c
index a1ce560..4927e36 100644
--- a/plugins/sslutils.c
+++ b/plugins/sslutils.c
@@ -45,6 +45,10 @@ int np_net_ssl_init_with_hostname(int sd, char *host_name) {
 }
 
 int np_net_ssl_init_with_hostname_and_version(int sd, char *host_name, int version) {
+	return np_net_ssl_init_with_hostname_version_and_certificate(sd, host_name, version, NULL, NULL);
+}
+
+int np_net_ssl_init_with_hostname_version_and_certificate(int sd, char *host_name, int version, char *cert, char *privkey) {
 	const SSL_METHOD *method = NULL;
 
 	switch (version) {
@@ -80,6 +84,14 @@ int np_net_ssl_init_with_hostname_and_version(int sd, char *host_name, int versi
 		printf("%s\n", _("CRITICAL - Cannot create SSL context."));
 		return STATE_CRITICAL;
 	}
+	if (cert && privkey) {
+		SSL_CTX_use_certificate_file(c, cert, SSL_FILETYPE_PEM);
+		SSL_CTX_use_PrivateKey_file(c, privkey, SSL_FILETYPE_PEM);
+		if (!SSL_CTX_check_private_key(c)) {
+			printf ("%s\n", _("CRITICAL - Private key does not seem to match certificate!\n"));
+			return STATE_CRITICAL;
+		}
+	}
 #ifdef SSL_OP_NO_TICKET
 	SSL_CTX_set_options(c, SSL_OP_NO_TICKET);
 #endif





More information about the Commits mailing list