summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2017-04-20 16:37:16 +0000
committerAndreas Baumann <mail@andreasbaumann.cc>2017-04-20 16:37:16 +0000
commit0d07ab80ab2fd80c7fc32c0adf7cc0d01028aec9 (patch)
tree258fc1a3a0f56d68d58287804c0ee26a5708ea8c
parent92f0f83a93ed718bded7153e0f5daa2f941a8834 (diff)
downloadmonitoring-plugins-0d07ab8.tar.gz
probing for SSL library used by libcurl and started improving the certificate check -C
-rw-r--r--plugins/check_curl.c186
1 files changed, 147 insertions, 39 deletions
diff --git a/plugins/check_curl.c b/plugins/check_curl.c
index b0026378..d3f3930f 100644
--- a/plugins/check_curl.c
+++ b/plugins/check_curl.c
@@ -91,6 +91,14 @@ typedef struct {
91 char *first_line; /* a copy of the first line */ 91 char *first_line; /* a copy of the first line */
92} curlhelp_statusline; 92} curlhelp_statusline;
93 93
94typedef enum curlhelp_ssl_library {
95 CURLHELP_SSL_LIBRARY_UNKNOWN,
96 CURLHELP_SSL_LIBRARY_OPENSSL,
97 CURLHELP_SSL_LIBRARY_LIBRESSL,
98 CURLHELP_SSL_LIBRARY_GNUTLS,
99 CURLHELP_SSL_LIBRARY_NSS
100} curlhelp_ssl_library;
101
94enum { 102enum {
95 REGS = 2, 103 REGS = 2,
96 MAX_RE_SIZE = 256 104 MAX_RE_SIZE = 256
@@ -160,12 +168,14 @@ int ssl_version = CURL_SSLVERSION_DEFAULT;
160char *client_cert = NULL; 168char *client_cert = NULL;
161char *client_privkey = NULL; 169char *client_privkey = NULL;
162char *ca_cert = NULL; 170char *ca_cert = NULL;
171int is_openssl_callback = FALSE;
163#ifdef HAVE_SSL 172#ifdef HAVE_SSL
164X509 *cert = NULL; 173X509 *cert = NULL;
165#endif 174#endif
166int no_body = FALSE; 175int no_body = FALSE;
167int maximum_age = -1; 176int maximum_age = -1;
168int address_family = AF_UNSPEC; 177int address_family = AF_UNSPEC;
178curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
169 179
170int process_arguments (int, char**); 180int process_arguments (int, char**);
171void handle_curl_option_return_code (CURLcode res, const char* option); 181void handle_curl_option_return_code (CURLcode res, const char* option);
@@ -179,6 +189,8 @@ void curlhelp_freewritebuffer (curlhelp_write_curlbuf*);
179int curlhelp_initreadbuffer (curlhelp_read_curlbuf *, const char *, size_t); 189int curlhelp_initreadbuffer (curlhelp_read_curlbuf *, const char *, size_t);
180int curlhelp_buffer_read_callback (void *, size_t , size_t , void *); 190int curlhelp_buffer_read_callback (void *, size_t , size_t , void *);
181void curlhelp_freereadbuffer (curlhelp_read_curlbuf *); 191void curlhelp_freereadbuffer (curlhelp_read_curlbuf *);
192curlhelp_ssl_library curlhelp_get_ssl_library (CURL*);
193const char* curlhelp_get_ssl_library_string (curlhelp_ssl_library);
182 194
183int curlhelp_parse_statusline (const char*, curlhelp_statusline *); 195int curlhelp_parse_statusline (const char*, curlhelp_statusline *);
184void curlhelp_free_statusline (curlhelp_statusline *); 196void curlhelp_free_statusline (curlhelp_statusline *);
@@ -368,25 +380,59 @@ check_http (void)
368 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0), "CURLOPT_SSL_VERIFYPEER"); 380 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0), "CURLOPT_SSL_VERIFYPEER");
369 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0), "CURLOPT_SSL_VERIFYHOST"); 381 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0), "CURLOPT_SSL_VERIFYHOST");
370 } 382 }
383
384 /* detect SSL library used by libcurl */
385 ssl_library = curlhelp_get_ssl_library (curl);
371 386
372 /* try hard to get a stack of certificates to verify against */ 387 /* try hard to get a stack of certificates to verify against */
373 if (check_cert) 388 if (check_cert)
374#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) 389#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1)
375 /* inform curl to report back certificates (this works for OpenSSL, NSS at least) */ 390 /* inform curl to report back certificates */
376 curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L); 391 switch (ssl_library) {
377#ifdef LIBCURL_USES_OPENSSL 392 case CURLHELP_SSL_LIBRARY_OPENSSL:
378 /* set callback to extract certificate with OpenSSL context function (works with 393 case CURLHELP_SSL_LIBRARY_LIBRESSL:
379 * OpenSSL only!) 394 /* set callback to extract certificate with OpenSSL context function (works with
380 */ 395 * OpenSSL-style libraries only!) */
381 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION"); 396#ifdef USE_OPENSSL
397 /* libcurl and monitoring plugins built with OpenSSL, good */
398 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION");
399 is_openssl_callback = TRUE;
400#else /* USE_OPENSSL */
382#endif /* USE_OPENSSL */ 401#endif /* USE_OPENSSL */
402 /* libcurl is built with OpenSSL, monitoring plugins, so falling
403 * back to manually extracting certificate information */
404 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
405 break;
406
407 case CURLHELP_SSL_LIBRARY_NSS:
408#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
409 /* NSS: support for CERTINFO is implemented since 7.34.0 */
410 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
411#else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
412 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library '%s' is too old)\n", curlhelp_get_ssl_library_string (ssl_library));
413#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
414 break;
415
416 case CURLHELP_SSL_LIBRARY_GNUTLS:
417#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0)
418 /* GnuTLS: support for CERTINFO is implemented since 7.42.0 */
419 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
420#else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
421 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library '%s' is too old)\n", curlhelp_get_ssl_library_string (ssl_library));
422#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
423 break;
424
425 case CURLHELP_SSL_LIBRARY_UNKNOWN:
426 default:
427 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (unknown SSL library '%s', must implement first)\n", curlhelp_get_ssl_library_string (ssl_library));
428 break;
429 }
383#else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */ 430#else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
384#ifdef LIBCURL_USES_OPENSSL 431 /* old libcurl, our only hope is OpenSSL, otherwise we are out of luck */
385 /* Too old curl library, hope we have OpenSSL */ 432 if (ssl_library == CURLHELP_SSL_LIBRARY_OPENSSL || ssl_library == CURLHELP_SSL_LIBRARY_LIBRESSL)
386 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION"); 433 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION");
387#else 434 else
388 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (no CURLOPT_SSL_CTX_FUNCTION, no OpenSSL library)\n"); 435 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (no CURLOPT_SSL_CTX_FUNCTION, no OpenSSL library or libcurl too old and has no CURLOPT_CERTINFO)\n");
389#endif /* LIBCURL_USES_OPENSSL */
390#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */ 436#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
391 437
392#endif /* LIBCURL_FEATURE_SSL */ 438#endif /* LIBCURL_FEATURE_SSL */
@@ -480,35 +526,44 @@ check_http (void)
480#ifdef LIBCURL_FEATURE_SSL 526#ifdef LIBCURL_FEATURE_SSL
481 if (use_ssl == TRUE) { 527 if (use_ssl == TRUE) {
482 if (check_cert == TRUE) { 528 if (check_cert == TRUE) {
483 if (verbose >= 2) 529 if (is_openssl_callback) {
484 printf ("**** REQUEST CERTIFICATES ****\n"); 530#ifdef HAVE_SSL
485 cert_ptr.to_info = NULL; 531 /* check certificate with OpenSSL functions, curl has been built against OpenSSL
486 res = curl_easy_getinfo (curl, CURLINFO_CERTINFO, &cert_ptr.to_info); 532 * and we actually have OpenSSL in the monitoring tools
487 if (!res && cert_ptr.to_info) { 533 */
488 int i; 534 result = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
489 for (i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) { 535 return result;
490 struct curl_slist *slist; 536#else /* HAVE_SSL */
491 for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; slist = slist->next) { 537 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL callback used and not linked against OpenSSL\n");
492 if (verbose >= 2) 538#endif /* HAVE_SSL */
493 printf ("%d ** %s\n", i, slist->data); 539 } else {
540 /* going with the libcurl CURLINFO data */
541 if (verbose >= 2)
542 printf ("**** REQUEST CERTIFICATES ****\n");
543 cert_ptr.to_info = NULL;
544 res = curl_easy_getinfo (curl, CURLINFO_CERTINFO, &cert_ptr.to_info);
545 if (!res && cert_ptr.to_info) {
546 int i;
547 for (i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) {
548 struct curl_slist *slist;
549 for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; slist = slist->next) {
550 if (verbose >= 2)
551 printf ("%d ** %s\n", i, slist->data);
552 }
494 } 553 }
554 } else {
555 snprintf (msg, DEFAULT_BUFFER_SIZE, _("Cannot retrieve certificates - cURL returned %d - %s"),
556 res, curl_easy_strerror(res));
557 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
495 } 558 }
496 } else { 559 if (verbose >= 2)
497 snprintf (msg, DEFAULT_BUFFER_SIZE, _("Cannot retrieve certificates - cURL returned %d - %s"), 560 printf ("**** REQUEST CERTIFICATES ****\n");
498 res, curl_easy_strerror(res)); 561 // TODO: either convert data to X509 certs we can check with np_net_ssl_check_certificate
499 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 562 // or do something on our own..
563 //~ result = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
564 //~ return result;
565 die (STATE_UNKNOWN, "HTTP UNKNOWN - CERTINFO certificate checks not implemented yet\n");
500 } 566 }
501 if (verbose >= 2)
502 printf ("**** REQUEST CERTIFICATES ****\n");
503 /* check certificate with OpenSSL functions, curl has been built against OpenSSL
504 * and we actually have OpenSSL in the monitoring tools
505 */
506#ifdef HAVE_SSL
507#ifdef LIBCURL_USES_OPENSSL
508 result = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
509#endif /* LIBCURL_USES_OPENSSL */
510#endif /* HAVE_SSL */
511 return result;
512 } 567 }
513 } 568 }
514#endif /* LIBCURL_FEATURE_SSL */ 569#endif /* LIBCURL_FEATURE_SSL */
@@ -1617,3 +1672,56 @@ check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFA
1617 1672
1618 return date_result; 1673 return date_result;
1619} 1674}
1675
1676/* TODO: is there a better way in libcurl to check for the SSL library? */
1677curlhelp_ssl_library
1678curlhelp_get_ssl_library (CURL* curl)
1679{
1680 curl_version_info_data* version_data;
1681 char *ssl_version;
1682 char *library;
1683 curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
1684
1685 version_data = curl_version_info (CURLVERSION_NOW);
1686 if (version_data == NULL) return CURLHELP_SSL_LIBRARY_UNKNOWN;
1687
1688 ssl_version = strdup (version_data->ssl_version);
1689 if (ssl_version == NULL ) return CURLHELP_SSL_LIBRARY_UNKNOWN;
1690
1691 library = strtok (ssl_version, "/");
1692 if (library == NULL) return CURLHELP_SSL_LIBRARY_UNKNOWN;
1693
1694 if (strcmp (library, "OpenSSL") == 0)
1695 ssl_library = CURLHELP_SSL_LIBRARY_OPENSSL;
1696 else if (strcmp (library, "LibreSSL") == 0)
1697 ssl_library = CURLHELP_SSL_LIBRARY_LIBRESSL;
1698 else if (strcmp (library, "GnuTLS") == 0)
1699 ssl_library = CURLHELP_SSL_LIBRARY_GNUTLS;
1700 else if (strcmp (library, "NSS") == 0)
1701 ssl_library = CURLHELP_SSL_LIBRARY_NSS;
1702
1703 if (verbose >= 2)
1704 printf ("* SSL library string is : %s %s (%d)\n", version_data->ssl_version, library, ssl_library);
1705
1706 free (ssl_version);
1707
1708 return ssl_library;
1709}
1710
1711const char*
1712curlhelp_get_ssl_library_string (curlhelp_ssl_library ssl_library)
1713{
1714 switch (ssl_library) {
1715 case CURLHELP_SSL_LIBRARY_OPENSSL:
1716 return "OpenSSL";
1717 case CURLHELP_SSL_LIBRARY_LIBRESSL:
1718 return "LibreSSL";
1719 case CURLHELP_SSL_LIBRARY_GNUTLS:
1720 return "GnuTLS";
1721 case CURLHELP_SSL_LIBRARY_NSS:
1722 return "NSS";
1723 case CURLHELP_SSL_LIBRARY_UNKNOWN:
1724 default:
1725 return "unknown";
1726 }
1727}