summaryrefslogtreecommitdiffstats
path: root/plugins/check_curl.c
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2017-04-19 14:36:01 +0200
committerSven Nierlein <sven@nierlein.de>2018-10-22 16:30:31 +0200
commit55e8d89b0a24dc8a1a3d6ea031a2189b1cf3f497 (patch)
treec09a0cbeb33d21aa8c33d4c8278fa230796a0f3e /plugins/check_curl.c
parentcee5f2777d022cb5333f6155c6bb54c77949225c (diff)
downloadmonitoring-plugins-55e8d89b0a24dc8a1a3d6ea031a2189b1cf3f497.tar.gz
some work on certificate checking for non-OpenSSL libraries
Diffstat (limited to 'plugins/check_curl.c')
-rw-r--r--plugins/check_curl.c88
1 files changed, 77 insertions, 11 deletions
diff --git a/plugins/check_curl.c b/plugins/check_curl.c
index ff79f15b..5ed47e2c 100644
--- a/plugins/check_curl.c
+++ b/plugins/check_curl.c
@@ -149,6 +149,10 @@ int onredirect = STATE_OK;
149int use_ssl = FALSE; 149int use_ssl = FALSE;
150int use_sni = TRUE; 150int use_sni = TRUE;
151int check_cert = FALSE; 151int check_cert = FALSE;
152union {
153 struct curl_slist* to_info;
154 struct curl_certinfo* to_certinfo;
155} cert_ptr;
152int ssl_version = CURL_SSLVERSION_DEFAULT; 156int ssl_version = CURL_SSLVERSION_DEFAULT;
153char *client_cert = NULL; 157char *client_cert = NULL;
154char *client_privkey = NULL; 158char *client_privkey = NULL;
@@ -212,6 +216,10 @@ main (int argc, char **argv)
212 216
213int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) 217int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
214{ 218{
219 /* TODO: we get all certificates of the chain, so which ones
220 * should we test?
221 * TODO: is the last certificate always the server certificate?
222 */
215 cert = X509_STORE_CTX_get_current_cert(x509_ctx); 223 cert = X509_STORE_CTX_get_current_cert(x509_ctx);
216 return 1; 224 return 1;
217} 225}
@@ -330,6 +338,8 @@ check_http (void)
330 /* set HTTP headers */ 338 /* set HTTP headers */
331 handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPHEADER, header_list ), "CURLOPT_HTTPHEADER"); 339 handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPHEADER, header_list ), "CURLOPT_HTTPHEADER");
332 340
341#ifdef LIBCURL_FEATURE_SSL
342
333 /* set SSL version, warn about unsecure or unsupported versions */ 343 /* set SSL version, warn about unsecure or unsupported versions */
334 if (use_ssl) { 344 if (use_ssl) {
335 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLVERSION, ssl_version), "CURLOPT_SSLVERSION"); 345 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLVERSION, ssl_version), "CURLOPT_SSLVERSION");
@@ -344,7 +354,7 @@ check_http (void)
344 /* per default if we have a CA verify both the peer and the 354 /* per default if we have a CA verify both the peer and the
345 * hostname in the certificate, can be switched off later */ 355 * hostname in the certificate, can be switched off later */
346 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CAINFO, ca_cert), "CURLOPT_CAINFO"); 356 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CAINFO, ca_cert), "CURLOPT_CAINFO");
347 handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 2), "CURLOPT_SSL_VERIFYPEER"); 357 handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 1), "CURLOPT_SSL_VERIFYPEER");
348 handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_SSL_VERIFYHOST, 2), "CURLOPT_SSL_VERIFYHOST"); 358 handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_SSL_VERIFYHOST, 2), "CURLOPT_SSL_VERIFYHOST");
349 } else { 359 } else {
350 /* backward-compatible behaviour, be tolerant in checks 360 /* backward-compatible behaviour, be tolerant in checks
@@ -354,11 +364,28 @@ check_http (void)
354 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0), "CURLOPT_SSL_VERIFYPEER"); 364 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0), "CURLOPT_SSL_VERIFYPEER");
355 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0), "CURLOPT_SSL_VERIFYHOST"); 365 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0), "CURLOPT_SSL_VERIFYHOST");
356 } 366 }
357 367
358 /* set callback to extract certificate */ 368 /* try hard to get a stack of certificates to verify against */
359 if(check_cert) { 369 if (check_cert)
370#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1)
371 /* inform curl to report back certificates (this works for OpenSSL, NSS at least) */
372 curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L);
373#ifdef USE_OPENSSL
374 /* set callback to extract certificate with OpenSSL context function (works with
375 * OpenSSL only!)
376 */
360 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION"); 377 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION");
361 } 378#endif /* USE_OPENSSL */
379#else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
380#ifdef USE_OPENSSL
381 /* Too old curl library, hope we have OpenSSL */
382 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION");
383#else
384 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (no CURLOPT_SSL_CTX_FUNCTION, no OpenSSL library)\n");
385#endif /* USE_OPENSSL */
386#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
387
388#endif /* HAVE_SSL */
362 389
363 /* set default or user-given user agent identification */ 390 /* set default or user-given user agent identification */
364 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_USERAGENT, user_agent), "CURLOPT_USERAGENT"); 391 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_USERAGENT, user_agent), "CURLOPT_USERAGENT");
@@ -402,8 +429,10 @@ check_http (void)
402 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)"); 429 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)");
403 else if (address_family == AF_INET) 430 else if (address_family == AF_INET)
404 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)"); 431 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)");
432#ifdef USE_IPV6
405 else if (address_family == AF_INET6) 433 else if (address_family == AF_INET6)
406 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)"); 434 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)");
435#endif
407 436
408 /* either send http POST data (any data, not only POST)*/ 437 /* either send http POST data (any data, not only POST)*/
409 if (!strcmp(http_method, "POST") ||!strcmp(http_method, "PUT")) { 438 if (!strcmp(http_method, "POST") ||!strcmp(http_method, "PUT")) {
@@ -444,14 +473,41 @@ check_http (void)
444 } 473 }
445 474
446 /* certificate checks */ 475 /* certificate checks */
447#ifdef HAVE_SSL 476#ifdef LIBCURL_FEATURE_SSL
448 if (use_ssl == TRUE) { 477 if (use_ssl == TRUE) {
449 if (check_cert == TRUE) { 478 if (check_cert == TRUE) {
479 if (verbose >= 2)
480 printf ("**** REQUEST CERTIFICATES ****\n");
481 cert_ptr.to_info = NULL;
482 res = curl_easy_getinfo (curl, CURLINFO_CERTINFO, &cert_ptr.to_info);
483 if (!res && cert_ptr.to_info) {
484 int i;
485 for (i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) {
486 struct curl_slist *slist;
487 for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; slist = slist->next) {
488 if (verbose >= 2)
489 printf ("%d ** %s\n", i, slist->data);
490 }
491 }
492 } else {
493 snprintf (msg, DEFAULT_BUFFER_SIZE, _("Cannot retrieve certificates - cURL returned %d - %s"),
494 res, curl_easy_strerror(res));
495 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
496 }
497 if (verbose >= 2)
498 printf ("**** REQUEST CERTIFICATES ****\n");
499 /* check certificate with OpenSSL functions, curl has been built against OpenSSL
500 * and we actually have OpenSSL in the monitoring tools
501 */
502#ifdef HAVE_SSL
503#ifdef USE_OPENSSL
450 result = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit); 504 result = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
451 return(result); 505#endif /* USE_OPENSSL */
506#endif /* HAVE_SSL */
507 return result;
452 } 508 }
453 } 509 }
454#endif /* HAVE_SSL */ 510#endif /* LIBCURL_FEATURE_SSL */
455 511
456 /* we got the data and we executed the request in a given time, so we can append 512 /* we got the data and we executed the request in a given time, so we can append
457 * performance data to the answer always 513 * performance data to the answer always
@@ -481,7 +537,6 @@ check_http (void)
481 (int)body_buf.buflen); 537 (int)body_buf.buflen);
482 } 538 }
483 539
484
485 /* return a CRITICAL status if we couldn't read any data */ 540 /* return a CRITICAL status if we couldn't read any data */
486 if (strlen(header_buf.buf) == 0 && strlen(body_buf.buf) == 0) 541 if (strlen(header_buf.buf) == 0 && strlen(body_buf.buf) == 0)
487 die (STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n")); 542 die (STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n"));
@@ -605,6 +660,16 @@ check_http (void)
605 /* make sure the page is of an appropriate size 660 /* make sure the page is of an appropriate size
606 * TODO: as far I can tell check_http gets the full size of header and 661 * TODO: as far I can tell check_http gets the full size of header and
607 * if -N is not given header+body. Does this make sense? 662 * if -N is not given header+body. Does this make sense?
663 *
664 * TODO: check_http.c had a get_length function, the question is really
665 * here what to use? the raw data size of the header_buf, the value of
666 * Content-Length, both and warn if they differ? Should the length be
667 * header+body or only body?
668 *
669 * One possible policy:
670 * - use header_buf.buflen (warning, if it mismatches to the Content-Length value
671 * - if -N (nobody) is given, use Content-Length only and hope the server set
672 * the value correcly
608 */ 673 */
609 page_len = header_buf.buflen + body_buf.buflen; 674 page_len = header_buf.buflen + body_buf.buflen;
610 if ((max_page_len > 0) && (page_len > max_page_len)) { 675 if ((max_page_len > 0) && (page_len > max_page_len)) {
@@ -637,8 +702,8 @@ check_http (void)
637 curlhelp_free_statusline(&status_line); 702 curlhelp_free_statusline(&status_line);
638 curl_easy_cleanup (curl); 703 curl_easy_cleanup (curl);
639 curl_global_cleanup (); 704 curl_global_cleanup ();
640 curlhelp_freewritebuffer(&body_buf); 705 curlhelp_freewritebuffer (&body_buf);
641 curlhelp_freewritebuffer(&header_buf); 706 curlhelp_freewritebuffer (&header_buf);
642 if (!strcmp (http_method, "PUT")) { 707 if (!strcmp (http_method, "PUT")) {
643 curlhelp_freereadbuffer (&put_buf); 708 curlhelp_freereadbuffer (&put_buf);
644 } 709 }
@@ -1493,6 +1558,7 @@ get_header_value (const struct phr_header* headers, const size_t nof_headers, co
1493 return NULL; 1558 return NULL;
1494} 1559}
1495 1560
1561/* TODO: use CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused); here */
1496static time_t 1562static time_t
1497parse_time_string (const char *string) 1563parse_time_string (const char *string)
1498{ 1564{