diff options
Diffstat (limited to 'plugins')
| -rw-r--r-- | plugins/check_curl.c | 88 |
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; | |||
| 149 | int use_ssl = FALSE; | 149 | int use_ssl = FALSE; |
| 150 | int use_sni = TRUE; | 150 | int use_sni = TRUE; |
| 151 | int check_cert = FALSE; | 151 | int check_cert = FALSE; |
| 152 | union { | ||
| 153 | struct curl_slist* to_info; | ||
| 154 | struct curl_certinfo* to_certinfo; | ||
| 155 | } cert_ptr; | ||
| 152 | int ssl_version = CURL_SSLVERSION_DEFAULT; | 156 | int ssl_version = CURL_SSLVERSION_DEFAULT; |
| 153 | char *client_cert = NULL; | 157 | char *client_cert = NULL; |
| 154 | char *client_privkey = NULL; | 158 | char *client_privkey = NULL; |
| @@ -212,6 +216,10 @@ main (int argc, char **argv) | |||
| 212 | 216 | ||
| 213 | int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) | 217 | int 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 */ | ||
| 1496 | static time_t | 1562 | static time_t |
| 1497 | parse_time_string (const char *string) | 1563 | parse_time_string (const char *string) |
| 1498 | { | 1564 | { |
