diff options
Diffstat (limited to 'contrib')
| -rw-r--r-- | contrib/check_http-with-client-certificate.c | 1567 | ||||
| -rw-r--r-- | contrib/check_linux_raid.pl | 20 | ||||
| -rw-r--r-- | contrib/check_nmap.py | 7 |
3 files changed, 18 insertions, 1576 deletions
diff --git a/contrib/check_http-with-client-certificate.c b/contrib/check_http-with-client-certificate.c deleted file mode 100644 index c47cbd4f..00000000 --- a/contrib/check_http-with-client-certificate.c +++ /dev/null | |||
| @@ -1,1567 +0,0 @@ | |||
| 1 | /**************************************************************************** | ||
| 2 | * | ||
| 3 | * Program: HTTP plugin for Nagios | ||
| 4 | * License: GPL | ||
| 5 | * | ||
| 6 | * License Information: | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 21 | * | ||
| 22 | *****************************************************************************/ | ||
| 23 | |||
| 24 | /**************************************************************************** | ||
| 25 | * | ||
| 26 | * check_http is derived from the original check_http provided by | ||
| 27 | * Ethan Galstad/Karl DeBisschop | ||
| 28 | * | ||
| 29 | * This provides some additional functionality including: | ||
| 30 | * - check server certificate against supplied hostname (Host: header) if any | ||
| 31 | * - check server certificate against local CA certificates (as browsers do) | ||
| 32 | * - authenticate with client certificate (and optional passphrase) | ||
| 33 | * - specify HTTP returncodes to return a status of WARNING or OK instead of | ||
| 34 | * CRITICAL (only global for 3xx or 4xx errors) | ||
| 35 | * - check only against HTTP status line and exit immediately if not matched | ||
| 36 | * | ||
| 37 | *****************************************************************************/ | ||
| 38 | |||
| 39 | const char *progname = "check_http"; | ||
| 40 | #define REVISION "$Revision: 1117 $" | ||
| 41 | #define CVSREVISION "1.24" | ||
| 42 | #define COPYRIGHT "2003" | ||
| 43 | #define AUTHORS "Fabian Pehla" | ||
| 44 | #define EMAIL "fabian@pehla.de" | ||
| 45 | |||
| 46 | #include "config.h" | ||
| 47 | #include "common.h" | ||
| 48 | #include "netutils.h" | ||
| 49 | #include "utils.h" | ||
| 50 | |||
| 51 | |||
| 52 | #define HELP_TXT_SUMMARY "\ | ||
| 53 | This plugin tests the HTTP service on the specified host. It can test\n\ | ||
| 54 | normal (http) and secure (https) servers, follow redirects, search for\n\ | ||
| 55 | strings and regular expressions, check connection times, and report on\n\ | ||
| 56 | certificate expiration times.\n" | ||
| 57 | |||
| 58 | #define HELP_TXT_OPTIONS "\ | ||
| 59 | -H <virtual host> -I <ip address> [-p <port>] [-u <uri>]\n\ | ||
| 60 | [-w <warn time>] [-c <critical time>] [-t <timeout>]\n\ | ||
| 61 | [-S] [-C <days>] [-a <basic auth>] [-A <certificate file>]\n\ | ||
| 62 | [-Z <ca certificate file>] [-e <expect>] [-E <expect only>]\n\ | ||
| 63 | [-s <string>] [-r <regex>] [-R <regex case insensitive>]\n\ | ||
| 64 | [-f (ok|warn|critical|follow)] [-g (ok|warn|critical)]\n" | ||
| 65 | |||
| 66 | #define HELP_TXT_LONGOPTIONS "\ | ||
| 67 | -H, --hostname=<virtual host>\n\ | ||
| 68 | FQDN host name argument for use in HTTP Host:-Header (virtual host)\n\ | ||
| 69 | If used together wich the -S option, the server certificate will\n\ | ||
| 70 | be checked against this hostname\n\ | ||
| 71 | -I, --ip-address=<address>\n\ | ||
| 72 | IP address or hostname for TCP connect (use IP to avoid DNS lookup)\n\ | ||
| 73 | -p, --port=<port>\n\ | ||
| 74 | Port number (default: %d)\n\ | ||
| 75 | -u, --url-path=<uri>\n\ | ||
| 76 | URL to request from host (default: %s)\n\ | ||
| 77 | -S, --ssl\n\ | ||
| 78 | Use SSL (default port: %d)\n\ | ||
| 79 | -C, --server-certificate-days=<days>\n\ | ||
| 80 | Minimum number of days a server certificate must be valid\n\ | ||
| 81 | No other check can be combined with this option\n\ | ||
| 82 | -a, --basic-auth=<username:password>\n\ | ||
| 83 | Colon separated username and password for basic authentication\n\ | ||
| 84 | -A, --client-certificate=<certificate file>\n\ | ||
| 85 | File containing X509 client certificate and key\n\ | ||
| 86 | -K, --passphrase=<passphrase>\n\ | ||
| 87 | Passphrase for the client certificate key\n\ | ||
| 88 | This option can only be used in combination with the -A option\n\ | ||
| 89 | -Z, --ca-certificate=<certificate file>\n\ | ||
| 90 | File containing certificates of trusted CAs\n\ | ||
| 91 | The server certificate will be checked against these CAs\n\ | ||
| 92 | -e, --http-expect=<expect string>\n\ | ||
| 93 | String to expect in HTTP response line (Default: %s)\n\ | ||
| 94 | -E, --http-expect-only=<expect only string>\n\ | ||
| 95 | String to expect in HTTP response line\n\ | ||
| 96 | No other checks are made, this either matches the response\n\ | ||
| 97 | or exits immediately\n\ | ||
| 98 | -s, --content-string=<string>\n\ | ||
| 99 | String to expect in content\n\ | ||
| 100 | -r, --content-ereg=<regex>\n\ | ||
| 101 | Regular expression to expect in content\n\ | ||
| 102 | -R, --content-eregi=<regex case insensitive>\n\ | ||
| 103 | Case insensitive regular expression to expect in content\n\ | ||
| 104 | -f, --onredirect=(ok|warning|critical|follow)\n\ | ||
| 105 | Follow a redirect (3xx) or return with a user defined state\n\ | ||
| 106 | Default: OK\n\ | ||
| 107 | -g, --onerror=(ok|warning|critical)\n\ | ||
| 108 | Status to return on a client error (4xx)\n\ | ||
| 109 | -m, --min=INTEGER\n\ | ||
| 110 | Minimum page size required (bytes)\n\ | ||
| 111 | -t, --timeout=<timeout>\n\ | ||
| 112 | Seconds before connection times out (default: %d)\n\ | ||
| 113 | -c, --critical=<critical time>\n\ | ||
| 114 | Response time to result in critical status (seconds)\n\ | ||
| 115 | -w, --warning=<warn time>\n\ | ||
| 116 | Response time to result in warning status (seconds)\n\ | ||
| 117 | -V, --version\n\ | ||
| 118 | Print version information\n\ | ||
| 119 | -v, --verbose\n\ | ||
| 120 | Show details for command-line debugging (do not use with nagios server)\n\ | ||
| 121 | -h, --help\n\ | ||
| 122 | Print detailed help screen\n" | ||
| 123 | |||
| 124 | |||
| 125 | |||
| 126 | #define HTTP_PORT 80 | ||
| 127 | #define DEFAULT_HTTP_URL_PATH "/" | ||
| 128 | #define DEFAULT_HTTP_EXPECT "HTTP/1." | ||
| 129 | #define DEFAULT_HTTP_METHOD "GET" | ||
| 130 | #define DEFAULT_HTTP_REDIRECT_STATE STATE_OK | ||
| 131 | #define DEFAULT_HTTP_CLIENT_ERROR_STATE STATE_WARNING | ||
| 132 | |||
| 133 | #define HTTP_TEMPLATE_REQUEST "%s%s %s HTTP/1.0\r\n" | ||
| 134 | #define HTTP_TEMPLATE_HEADER_USERAGENT "%sUser-Agent: %s/%s (nagios-plugins %s)\r\n" | ||
| 135 | #define HTTP_TEMPLATE_HEADER_HOST "%sHost: %s\r\n" | ||
| 136 | #define HTTP_TEMPLATE_HEADER_AUTH "%sAuthorization: Basic %s\r\n" | ||
| 137 | |||
| 138 | /* fill in printf with protocol_text(use_ssl), state_text(state), page->status, elapsed_time */ | ||
| 139 | #define RESULT_TEMPLATE_STATUS_RESPONSE_TIME "%s %s: %s - %7.3f seconds response time|time=%7.3f\n" | ||
| 140 | #define RESULT_TEMPLATE_RESPONSE_TIME "%s %s: %7.3f seconds response time|time=%7.3f\n" | ||
| 141 | |||
| 142 | #ifdef HAVE_SSL | ||
| 143 | |||
| 144 | #ifdef HAVE_SSL_H | ||
| 145 | #include <rsa.h> | ||
| 146 | #include <crypto.h> | ||
| 147 | #include <x509.h> | ||
| 148 | #include <pem.h> | ||
| 149 | #include <ssl.h> | ||
| 150 | #include <err.h> | ||
| 151 | #include <rand.h> | ||
| 152 | #endif | ||
| 153 | |||
| 154 | #ifdef HAVE_OPENSSL_SSL_H | ||
| 155 | #include <openssl/rsa.h> | ||
| 156 | #include <openssl/crypto.h> | ||
| 157 | #include <openssl/x509.h> | ||
| 158 | #include <openssl/pem.h> | ||
| 159 | #include <openssl/ssl.h> | ||
| 160 | #include <openssl/err.h> | ||
| 161 | #include <openssl/rand.h> | ||
| 162 | #endif | ||
| 163 | |||
| 164 | #define HTTPS_PORT 443 | ||
| 165 | #endif | ||
| 166 | |||
| 167 | #ifdef HAVE_REGEX_H | ||
| 168 | #include <regex.h> | ||
| 169 | #define REGEX_REGS 2 | ||
| 170 | #define MAX_REGEX_SIZE 256 | ||
| 171 | #endif | ||
| 172 | |||
| 173 | #define chk_protocol(protocol) ( strstr( protocol, "https" ) ? TRUE : FALSE ); | ||
| 174 | #define protocol_std_port(use_ssl) ( use_ssl ? HTTPS_PORT : HTTP_PORT ); | ||
| 175 | #define protocol_text(use_ssl) ( use_ssl ? "HTTPS" : "HTTP" ) | ||
| 176 | |||
| 177 | #define MAX_IPV4_HOSTLENGTH 64 | ||
| 178 | #define HTTP_HEADER_LOCATION_MATCH "%*[Ll]%*[Oo]%*[Cc]%*[Aa]%*[Tt]%*[Ii]%*[Oo]%*[Nn]: " | ||
| 179 | #define HTTP_HEADER_PROTOCOL_MATCH "%[HTPShtps]://" | ||
| 180 | #define HTTP_HEADER_HOSTNAME_MATCH "%[a-zA-Z0-9.-]" | ||
| 181 | #define HTTP_HEADER_PORT_MATCH ":%[0-9]" | ||
| 182 | #define HTTP_HEADER_URL_PATH_MATCH "%[/a-zA-Z0-9._-=@,]" | ||
| 183 | |||
| 184 | /* | ||
| 185 | ************************************************************************ | ||
| 186 | * GLOBAL VARIABLE/POINTER DEFINITIONS * | ||
| 187 | ************************************************************************ | ||
| 188 | */ | ||
| 189 | |||
| 190 | /* misc variables */ | ||
| 191 | int verbose = FALSE; | ||
| 192 | |||
| 193 | /* time thresholds to determine exit code */ | ||
| 194 | int use_warning_interval = FALSE; | ||
| 195 | double warning_interval = 0; | ||
| 196 | int use_critical_interval = FALSE; | ||
| 197 | double critical_interval = 0; | ||
| 198 | double elapsed_time = 0; | ||
| 199 | struct timeval start_tv; | ||
| 200 | |||
| 201 | /* variables concerning the server host */ | ||
| 202 | int use_server_hostname = FALSE; | ||
| 203 | char *server_hostname = ""; // hostname for use in HTTPs Host: header | ||
| 204 | char *server_host = ""; // hostname or ip address for tcp connect | ||
| 205 | int use_server_port = FALSE; | ||
| 206 | int server_port = HTTP_PORT; | ||
| 207 | |||
| 208 | int use_basic_auth = FALSE; | ||
| 209 | char basic_auth[MAX_INPUT_BUFFER] = ""; | ||
| 210 | |||
| 211 | /* variables concerning server responce */ | ||
| 212 | struct pageref { | ||
| 213 | char *content; | ||
| 214 | size_t size; | ||
| 215 | char *status; | ||
| 216 | char *header; | ||
| 217 | char *body; | ||
| 218 | }; | ||
| 219 | |||
| 220 | /* variables concerning ssl connections */ | ||
| 221 | int use_ssl = FALSE; | ||
| 222 | #ifdef HAVE_SSL | ||
| 223 | int server_certificate_min_days_valid = 0; | ||
| 224 | int check_server_certificate = FALSE; | ||
| 225 | X509 *server_certificate; // structure containing server certificate | ||
| 226 | int use_client_certificate = FALSE; | ||
| 227 | char *client_certificate_file = NULL; | ||
| 228 | int use_client_certificate_passphrase = FALSE; | ||
| 229 | char *client_certificate_passphrase = NULL; | ||
| 230 | int use_ca_certificate = FALSE; | ||
| 231 | char *ca_certificate_file = NULL; | ||
| 232 | |||
| 233 | BIO *bio_err = 0; // error write context | ||
| 234 | #endif | ||
| 235 | |||
| 236 | |||
| 237 | /* variables concerning check behaviour */ | ||
| 238 | char *http_method = DEFAULT_HTTP_METHOD; | ||
| 239 | char *http_url_path = ""; | ||
| 240 | int use_http_post_data = FALSE; | ||
| 241 | char *http_post_data = ""; | ||
| 242 | int use_min_content_length = FALSE; | ||
| 243 | int min_content_length = 0; | ||
| 244 | int use_http_expect_only = FALSE; | ||
| 245 | char http_expect[MAX_INPUT_BUFFER] = DEFAULT_HTTP_EXPECT; | ||
| 246 | int check_content_string = FALSE; | ||
| 247 | char content_string[MAX_INPUT_BUFFER] = ""; | ||
| 248 | int http_redirect_state = DEFAULT_HTTP_REDIRECT_STATE; | ||
| 249 | int http_client_error_state = DEFAULT_HTTP_CLIENT_ERROR_STATE; | ||
| 250 | |||
| 251 | #ifdef HAVE_REGEX_H | ||
| 252 | regex_t regex_preg; | ||
| 253 | regmatch_t regex_pmatch[REGEX_REGS]; | ||
| 254 | int check_content_regex = FALSE; | ||
| 255 | char content_regex[MAX_REGEX_SIZE] = ""; | ||
| 256 | int regex_cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE; | ||
| 257 | int regex_error = 0; | ||
| 258 | char regex_error_buffer[MAX_INPUT_BUFFER] = ""; | ||
| 259 | #endif | ||
| 260 | |||
| 261 | |||
| 262 | |||
| 263 | /* | ||
| 264 | ************************************************************************ | ||
| 265 | * FUNCTION PROTOTYPES * | ||
| 266 | ************************************************************************ | ||
| 267 | */ | ||
| 268 | |||
| 269 | void print_usage( void ); | ||
| 270 | void print_help( void ); | ||
| 271 | int process_arguments (int, char **); | ||
| 272 | int http_request( int sock, struct pageref *page); | ||
| 273 | |||
| 274 | int parse_http_response( struct pageref *page ); | ||
| 275 | int check_http_response( struct pageref *page ); | ||
| 276 | int check_http_content( struct pageref *page ); | ||
| 277 | int prepare_follow_redirect( struct pageref *page ); | ||
| 278 | |||
| 279 | static char *base64 (char *bin, int len); | ||
| 280 | |||
| 281 | #ifdef HAVE_SSL | ||
| 282 | int ssl_terminate( int state, char *string ); | ||
| 283 | static int passwd_cb( char *buf, int num, int rwflag, void *userdata ); | ||
| 284 | static void sigpipe_handle( int x ); | ||
| 285 | SSL_CTX * initialize_ssl_ctx( void ); | ||
| 286 | void destroy_ssl_ctx( SSL_CTX *ctx ); | ||
| 287 | int fetch_server_certificate( SSL *ssl ); | ||
| 288 | int check_server_certificate_chain( SSL *ssl ); | ||
| 289 | int check_server_certificate_hostname( void ); | ||
| 290 | int check_server_certificate_expires( void ); | ||
| 291 | int https_request( SSL_CTX *ctx, SSL *ssl, struct pageref *page ); | ||
| 292 | #endif | ||
| 293 | |||
| 294 | /* | ||
| 295 | ************************************************************************ | ||
| 296 | * IMPLEMENTATION * | ||
| 297 | ************************************************************************ | ||
| 298 | */ | ||
| 299 | |||
| 300 | /* | ||
| 301 | * main() | ||
| 302 | * | ||
| 303 | * PSEUDOCODE OF HOW MAIN IS SUPPOSED TO WORK | ||
| 304 | * | ||
| 305 | * process command line arguments including sanity check | ||
| 306 | * initialize alarm signal handling | ||
| 307 | * if use_ssl | ||
| 308 | * build ssl context | ||
| 309 | * LOOP: | ||
| 310 | * make tcp connection | ||
| 311 | * if use_ssl | ||
| 312 | * make ssl connection | ||
| 313 | * if use_server_hostname | ||
| 314 | * check if certificate matches hostname | ||
| 315 | * if check_server_certificate | ||
| 316 | * check expiration date of server certificate | ||
| 317 | * return STATUS | ||
| 318 | * else | ||
| 319 | * request http page | ||
| 320 | * handle ssl rehandshake | ||
| 321 | * close ssl connection | ||
| 322 | * else | ||
| 323 | * request http page | ||
| 324 | * close tcp connection | ||
| 325 | * analyze http page | ||
| 326 | * if follow on redirect | ||
| 327 | * repeat LOOP | ||
| 328 | * end of LOOP | ||
| 329 | * destroy ssl context | ||
| 330 | */ | ||
| 331 | int | ||
| 332 | main (int argc, char **argv) | ||
| 333 | { | ||
| 334 | int result = STATE_UNKNOWN; | ||
| 335 | int sock; | ||
| 336 | struct pageref page; | ||
| 337 | #ifdef HAVE_SSL | ||
| 338 | SSL_CTX *ctx; | ||
| 339 | SSL *ssl; | ||
| 340 | BIO *sbio; | ||
| 341 | #endif | ||
| 342 | |||
| 343 | if ( process_arguments(argc, argv) == ERROR ) | ||
| 344 | usage( "check_http: could not parse arguments\n" ); | ||
| 345 | |||
| 346 | #ifdef HAVE_SSL | ||
| 347 | /* build SSL context if required: | ||
| 348 | * a) either we use ssl from the beginning OR | ||
| 349 | * b) or we follor redirects wich may lead os to a ssl page | ||
| 350 | */ | ||
| 351 | if ( use_ssl || ( http_redirect_state == STATE_DEPENDENT ) ) | ||
| 352 | ctx=initialize_ssl_ctx(); | ||
| 353 | #endif | ||
| 354 | |||
| 355 | /* Loop around 3xx onredirect=follow */ | ||
| 356 | do { | ||
| 357 | |||
| 358 | /* | ||
| 359 | * initialize alarm signal handling, set socket timeout, start timer | ||
| 360 | * socket_timeout and socket_timeout_alarm_handler are defined in | ||
| 361 | * netutils.c | ||
| 362 | */ | ||
| 363 | (void) signal( SIGALRM, socket_timeout_alarm_handler ); | ||
| 364 | (void) alarm( socket_timeout ); | ||
| 365 | gettimeofday( &start_tv, NULL ); | ||
| 366 | |||
| 367 | /* make a tcp connection */ | ||
| 368 | result = my_tcp_connect( server_host, server_port, &sock ); | ||
| 369 | |||
| 370 | /* result of tcp connect */ | ||
| 371 | if ( result == STATE_OK ) | ||
| 372 | { | ||
| 373 | #ifdef HAVE_SSL | ||
| 374 | /* make a ssl connection */ | ||
| 375 | if ( use_ssl ) { | ||
| 376 | ssl=SSL_new( ctx ); | ||
| 377 | sbio=BIO_new_socket( sock, BIO_NOCLOSE ); | ||
| 378 | SSL_set_bio( ssl, sbio, sbio); | ||
| 379 | if ( SSL_connect( ssl ) <= 0 ) | ||
| 380 | ssl_terminate( STATE_CRITICAL, "check_http: SSL connect error" ); | ||
| 381 | |||
| 382 | /* fetch server certificate */ | ||
| 383 | result = fetch_server_certificate( ssl ); | ||
| 384 | |||
| 385 | /* verify server certificate against CAs */ | ||
| 386 | if ( ( result == STATE_OK ) && use_ca_certificate ) { | ||
| 387 | result = check_server_certificate_chain( ssl ); | ||
| 388 | } | ||
| 389 | |||
| 390 | /* check if certificate matches hostname */ | ||
| 391 | if ( ( result == STATE_OK ) && use_server_hostname ) { | ||
| 392 | result = check_server_certificate_hostname(); | ||
| 393 | } | ||
| 394 | |||
| 395 | if ( result == STATE_OK ) { | ||
| 396 | /* check server certificate expire date */ | ||
| 397 | if ( check_server_certificate ) { | ||
| 398 | result = check_server_certificate_expires(); | ||
| 399 | /* OR: perform http request */ | ||
| 400 | } else { | ||
| 401 | result = https_request( ctx, ssl, (struct pageref *) &page ); | ||
| 402 | } | ||
| 403 | } | ||
| 404 | SSL_shutdown( ssl ); | ||
| 405 | SSL_free( ssl ); | ||
| 406 | } else { | ||
| 407 | #endif | ||
| 408 | /* HTTP implementation */ | ||
| 409 | result = http_request( sock, (struct pageref *) &page ); | ||
| 410 | #ifdef HAVE_SSL | ||
| 411 | } | ||
| 412 | #endif | ||
| 413 | /* stop timer and calculate elapsed_time */ | ||
| 414 | elapsed_time = delta_time( start_tv ); | ||
| 415 | |||
| 416 | /* close the tcp connection */ | ||
| 417 | close( sock ); | ||
| 418 | |||
| 419 | /* reset the alarm */ | ||
| 420 | alarm( 0 ); | ||
| 421 | |||
| 422 | /* analyze http page */ | ||
| 423 | /* TO DO */ | ||
| 424 | if ( result == STATE_OK ) | ||
| 425 | result = parse_http_response( (struct pageref *) &page ); | ||
| 426 | |||
| 427 | if ( result == STATE_OK ) | ||
| 428 | result = check_http_response( (struct pageref *) &page ); | ||
| 429 | |||
| 430 | switch ( result ) { | ||
| 431 | case STATE_OK: | ||
| 432 | /* weiter geht's */ | ||
| 433 | result = check_http_content( (struct pageref *) &page ); | ||
| 434 | break; | ||
| 435 | case STATE_DEPENDENT: | ||
| 436 | /* try to determine redirect parameters */ | ||
| 437 | result = prepare_follow_redirect( (struct pageref *) &page ); | ||
| 438 | break; | ||
| 439 | } | ||
| 440 | |||
| 441 | } else { | ||
| 442 | /* some error occured while trying to make a tcp connect */ | ||
| 443 | exit( result ); | ||
| 444 | } | ||
| 445 | |||
| 446 | } while ( result == STATE_DEPENDENT ); // end of onredirect loop | ||
| 447 | |||
| 448 | /* destroy SSL context */ | ||
| 449 | #ifdef HAVE_SSL | ||
| 450 | if ( use_ssl || ( http_redirect_state == STATE_DEPENDENT ) ) | ||
| 451 | destroy_ssl_ctx( ctx ); | ||
| 452 | #endif | ||
| 453 | |||
| 454 | /* if we ever get to this point, everything went fine */ | ||
| 455 | printf( RESULT_TEMPLATE_STATUS_RESPONSE_TIME, | ||
| 456 | protocol_text( use_ssl ), | ||
| 457 | state_text( result ), | ||
| 458 | page.status, | ||
| 459 | elapsed_time, | ||
| 460 | elapsed_time ); | ||
| 461 | |||
| 462 | return result; | ||
| 463 | } | ||
| 464 | |||
| 465 | |||
| 466 | void | ||
| 467 | print_help( void ) | ||
| 468 | { | ||
| 469 | print_revision( progname, REVISION ); | ||
| 470 | printf | ||
| 471 | ( "Copyright (c) %s %s <%s>\n\n%s\n", | ||
| 472 | COPYRIGHT, AUTHORS, EMAIL, HELP_TXT_SUMMARY ); | ||
| 473 | print_usage(); | ||
| 474 | printf( "NOTE: One or both of -H and -I must be specified\n" ); | ||
| 475 | printf( "\nOptions:\n" HELP_TXT_LONGOPTIONS "\n", | ||
| 476 | HTTP_PORT, DEFAULT_HTTP_URL_PATH, HTTPS_PORT, | ||
| 477 | DEFAULT_HTTP_EXPECT, DEFAULT_SOCKET_TIMEOUT ); | ||
| 478 | #ifdef HAVE_SSL | ||
| 479 | //printf( SSLDESCRIPTION ); | ||
| 480 | #endif | ||
| 481 | } | ||
| 482 | |||
| 483 | |||
| 484 | void | ||
| 485 | print_usage( void ) | ||
| 486 | { | ||
| 487 | printf( "Usage:\n" " %s %s\n" | ||
| 488 | #ifdef HAVE_GETOPT_H | ||
| 489 | " %s (-h | --help) for detailed help\n" | ||
| 490 | " %s (-V | --version) for version information\n", | ||
| 491 | #else | ||
| 492 | " %s -h for detailed help\n" | ||
| 493 | " %s -V for version information\n", | ||
| 494 | #endif | ||
| 495 | progname, HELP_TXT_OPTIONS, progname, progname ); | ||
| 496 | } | ||
| 497 | |||
| 498 | |||
| 499 | /* | ||
| 500 | * process_arguments() | ||
| 501 | * | ||
| 502 | * process command line arguments either using getopt_long or getopt | ||
| 503 | * (parsing long argumants manually) | ||
| 504 | */ | ||
| 505 | int | ||
| 506 | process_arguments( int argc, char **argv ) | ||
| 507 | { | ||
| 508 | int c, i = 1; | ||
| 509 | extern char *optarg; | ||
| 510 | |||
| 511 | #ifdef HAVE_GETOPT_H | ||
| 512 | int option_index = 0; | ||
| 513 | static struct option long_options[] = { | ||
| 514 | STD_LONG_OPTS, | ||
| 515 | {"file", required_argument, 0, 'F'}, | ||
| 516 | {"ip-address", required_argument, 0, 'I'}, | ||
| 517 | {"port", required_argument, 0, 'p'}, | ||
| 518 | {"url-path", required_argument, 0, 'u'}, | ||
| 519 | {"post-data", required_argument, 0, 'P'}, | ||
| 520 | {"ssl", no_argument, 0, 'S'}, | ||
| 521 | {"server-certificate-days", required_argument, 0, 'C'}, | ||
| 522 | {"basic-auth", required_argument, 0, 'a'}, | ||
| 523 | {"client-certificate", required_argument, 0, 'A'}, | ||
| 524 | {"passphrase", required_argument, 0, 'K'}, | ||
| 525 | {"ca-certificate", required_argument, 0, 'Z'}, | ||
| 526 | {"http-expect", required_argument, 0, 'e'}, | ||
| 527 | {"http-expect-only", required_argument, 0, 'E'}, | ||
| 528 | {"content-string", required_argument, 0, 's'}, | ||
| 529 | {"content-ereg-linespan", required_argument, 0, 'l'}, | ||
| 530 | {"content-ereg", required_argument, 0, 'r'}, | ||
| 531 | {"content-eregi", required_argument, 0, 'R'}, | ||
| 532 | {"onredirect", required_argument, 0, 'f'}, | ||
| 533 | {"onerror", required_argument, 0, 'g'}, | ||
| 534 | {"min", required_argument, 0, 'm'}, | ||
| 535 | {0, 0, 0, 0} | ||
| 536 | }; | ||
| 537 | #endif | ||
| 538 | |||
| 539 | |||
| 540 | /* convert commonly used arguments to their equivalent standard options */ | ||
| 541 | for (c = 1; c < argc; c++) { | ||
| 542 | if ( strcmp( "-to", argv[c]) == 0 ) | ||
| 543 | strcpy( argv[c], "-t" ); | ||
| 544 | if ( strcmp( "-hn", argv[c]) == 0 ) | ||
| 545 | strcpy( argv[c], "-H" ); | ||
| 546 | if ( strcmp( "-wt", argv[c]) == 0 ) | ||
| 547 | strcpy( argv[c], "-w" ); | ||
| 548 | if ( strcmp( "-ct", argv[c]) == 0 ) | ||
| 549 | strcpy( argv[c], "-c" ); | ||
| 550 | } | ||
| 551 | |||
| 552 | #define OPTCHARS "Vvht:c:w:H:F:I:p:u:P:SC:a:A:K:Z:e:E:s:r:R:f:g:lm:" | ||
| 553 | |||
| 554 | |||
| 555 | while (1) { | ||
| 556 | |||
| 557 | #ifdef HAVE_GETOPT_H | ||
| 558 | c = getopt_long( argc, argv, OPTCHARS, long_options, &option_index ); | ||
| 559 | #else | ||
| 560 | c = getopt( argc, argv, OPTCHARS ); | ||
| 561 | #endif | ||
| 562 | |||
| 563 | if ( ( c == -1 ) || ( c == EOF ) ) { | ||
| 564 | break; | ||
| 565 | } | ||
| 566 | |||
| 567 | switch (c) { | ||
| 568 | case '?': /* usage */ | ||
| 569 | usage2( "unknown argument", optarg ); | ||
| 570 | break; | ||
| 571 | |||
| 572 | /* Standard options */ | ||
| 573 | case 'h': /* help */ | ||
| 574 | print_help(); | ||
| 575 | exit( STATE_OK ); | ||
| 576 | break; | ||
| 577 | case 'V': /* version */ | ||
| 578 | print_revision( progname, REVISION ); | ||
| 579 | exit( STATE_OK ); | ||
| 580 | break; | ||
| 581 | case 'v': /* verbose */ | ||
| 582 | verbose = TRUE; | ||
| 583 | break; | ||
| 584 | case 't': /* timeout period */ | ||
| 585 | if ( !is_intnonneg( optarg ) ) | ||
| 586 | usage2( "timeout interval must be a non-negative integer", optarg ); | ||
| 587 | /* socket_timeout is defined in netutils.h and defaults to | ||
| 588 | * DEFAULT_SOCKET_TIMEOUT from common.h | ||
| 589 | */ | ||
| 590 | socket_timeout = atoi( optarg ); | ||
| 591 | break; | ||
| 592 | case 'c': /* critical time threshold */ | ||
| 593 | if ( !is_nonnegative( optarg ) ) | ||
| 594 | usage2( "invalid critical threshold", optarg ); | ||
| 595 | critical_interval = strtod( optarg, NULL ); | ||
| 596 | use_critical_interval = TRUE; | ||
| 597 | break; | ||
| 598 | case 'w': /* warning time threshold */ | ||
| 599 | if ( !is_nonnegative( optarg ) ) | ||
| 600 | usage2( "invalid warning threshold", optarg ); | ||
| 601 | warning_interval = strtod( optarg, NULL ); | ||
| 602 | use_warning_interval = TRUE; | ||
| 603 | break; | ||
| 604 | case 'H': /* Host Name (virtual host) */ | ||
| 605 | /* this rejects FQDNs, so we leave it for now... | ||
| 606 | *if ( !is_hostname( optarg ) ) | ||
| 607 | * usage2( "invalid hostname", optarg ); | ||
| 608 | */ | ||
| 609 | xasprintf( &server_hostname, "%s", optarg ); | ||
| 610 | use_server_hostname = TRUE; | ||
| 611 | break; | ||
| 612 | case 'F': /* File (dummy) */ | ||
| 613 | break; | ||
| 614 | /* End of standard options */ | ||
| 615 | |||
| 616 | |||
| 617 | case 'I': /* Server IP-address or Hostname */ | ||
| 618 | /* this rejects FQDNs, so we leave it for now... | ||
| 619 | *if ( !is_host( optarg ) ) | ||
| 620 | * usage2( "invalid ip address or hostname", optarg ) | ||
| 621 | */ | ||
| 622 | xasprintf( &server_host, "%s", optarg ); | ||
| 623 | break; | ||
| 624 | case 'p': /* Server port */ | ||
| 625 | if ( !is_intnonneg( optarg ) ) | ||
| 626 | usage2( "invalid port number", optarg ); | ||
| 627 | server_port = atoi( optarg ); | ||
| 628 | use_server_port = TRUE; | ||
| 629 | break; | ||
| 630 | case 'S': /* use SSL */ | ||
| 631 | #ifdef HAVE_SSL | ||
| 632 | use_ssl = TRUE; | ||
| 633 | if ( use_server_port == FALSE ) | ||
| 634 | server_port = HTTPS_PORT; | ||
| 635 | #else | ||
| 636 | usage( "check_http: invalid option - SSL is not available\n" ); | ||
| 637 | #endif | ||
| 638 | break; | ||
| 639 | case 'C': /* Server certificate warning time threshold */ | ||
| 640 | #ifdef HAVE_SSL | ||
| 641 | if ( !is_intnonneg( optarg ) ) | ||
| 642 | usage2( "invalid certificate expiration period", optarg ); | ||
| 643 | server_certificate_min_days_valid = atoi( optarg ); | ||
| 644 | check_server_certificate = TRUE; | ||
| 645 | #else | ||
| 646 | usage( "check_http: invalid option - SSL is not available\n" ); | ||
| 647 | #endif | ||
| 648 | break; | ||
| 649 | case 'a': /* basic authorization info */ | ||
| 650 | strncpy( basic_auth, optarg, MAX_INPUT_BUFFER - 1 ); | ||
| 651 | basic_auth[MAX_INPUT_BUFFER - 1] = 0; | ||
| 652 | use_basic_auth = TRUE; | ||
| 653 | break; | ||
| 654 | case 'A': /* client certificate */ | ||
| 655 | #ifdef HAVE_SSL | ||
| 656 | xasprintf( &client_certificate_file, "%s", optarg ); | ||
| 657 | use_client_certificate = TRUE; | ||
| 658 | #else | ||
| 659 | usage( "check_http: invalid option - SSL is not available\n" ); | ||
| 660 | #endif | ||
| 661 | break; | ||
| 662 | case 'K': /* client certificate passphrase */ | ||
| 663 | #ifdef HAVE_SSL | ||
| 664 | xasprintf( &client_certificate_passphrase, "%s", optarg ); | ||
| 665 | use_client_certificate_passphrase = TRUE; | ||
| 666 | #else | ||
| 667 | usage( "check_http: invalid option - SSL is not available\n" ); | ||
| 668 | #endif | ||
| 669 | case 'Z': /* valid CA certificates */ | ||
| 670 | #ifdef HAVE_SSL | ||
| 671 | xasprintf( &ca_certificate_file, "%s", optarg ); | ||
| 672 | use_ca_certificate = TRUE; | ||
| 673 | #else | ||
| 674 | usage( "check_http: invalid option - SSL is not available\n" ); | ||
| 675 | #endif | ||
| 676 | break; | ||
| 677 | case 'u': /* URL PATH */ | ||
| 678 | xasprintf( &http_url_path, "%s", optarg ); | ||
| 679 | break; | ||
| 680 | case 'P': /* POST DATA */ | ||
| 681 | xasprintf( &http_post_data, "%s", optarg ); | ||
| 682 | use_http_post_data = TRUE; | ||
| 683 | xasprintf( &http_method, "%s", "POST" ); | ||
| 684 | break; | ||
| 685 | case 'e': /* expected string in first line of HTTP response */ | ||
| 686 | strncpy( http_expect , optarg, MAX_INPUT_BUFFER - 1 ); | ||
| 687 | http_expect[MAX_INPUT_BUFFER - 1] = 0; | ||
| 688 | break; | ||
| 689 | case 'E': /* expected string in first line of HTTP response and process no other check*/ | ||
| 690 | strncpy( http_expect , optarg, MAX_INPUT_BUFFER - 1 ); | ||
| 691 | http_expect[MAX_INPUT_BUFFER - 1] = 0; | ||
| 692 | use_http_expect_only = TRUE; | ||
| 693 | break; | ||
| 694 | case 's': /* expected (sub-)string in content */ | ||
| 695 | strncpy( content_string , optarg, MAX_INPUT_BUFFER - 1 ); | ||
| 696 | content_string[MAX_INPUT_BUFFER - 1] = 0; | ||
| 697 | check_content_string = TRUE; | ||
| 698 | break; | ||
| 699 | case 'l': /* regex linespan */ | ||
| 700 | #ifdef HAVE_REGEX_H | ||
| 701 | regex_cflags &= ~REG_NEWLINE; | ||
| 702 | #else | ||
| 703 | usage( "check_http: call for regex which was not a compiled option\n" ); | ||
| 704 | #endif | ||
| 705 | break; | ||
| 706 | case 'R': /* expected case insensitive regular expression in content */ | ||
| 707 | #ifdef HAVE_REGEX_H | ||
| 708 | regex_cflags |= REG_ICASE; | ||
| 709 | #else | ||
| 710 | usage( "check_http: call for regex which was not a compiled option\n" ); | ||
| 711 | #endif | ||
| 712 | case 'r': /* expected regular expression in content */ | ||
| 713 | #ifdef HAVE_REGEX_H | ||
| 714 | strncpy( content_regex , optarg, MAX_REGEX_SIZE - 1 ); | ||
| 715 | content_regex[MAX_REGEX_SIZE - 1] = 0; | ||
| 716 | check_content_regex = TRUE; | ||
| 717 | regex_error = regcomp( ®ex_preg, content_regex, regex_cflags ); | ||
| 718 | if ( regex_error != 0 ) { | ||
| 719 | regerror( regex_error, ®ex_preg, regex_error_buffer, MAX_INPUT_BUFFER ); | ||
| 720 | printf( "Could Not Compile Regular Expression: %s", regex_error_buffer ); | ||
| 721 | return ERROR; | ||
| 722 | } | ||
| 723 | #else | ||
| 724 | usage( "check_http: call for regex which was not a compiled option\n" ); | ||
| 725 | #endif | ||
| 726 | break; | ||
| 727 | case 'f': /* onredirect (3xx errors) */ | ||
| 728 | if ( !strcmp( optarg, "follow" ) ) | ||
| 729 | http_redirect_state = STATE_DEPENDENT; | ||
| 730 | if ( !strcmp( optarg, "unknown" ) ) | ||
| 731 | http_redirect_state = STATE_UNKNOWN; | ||
| 732 | if ( !strcmp( optarg, "ok" ) ) | ||
| 733 | http_redirect_state = STATE_OK; | ||
| 734 | if ( !strcmp( optarg, "warning" ) ) | ||
| 735 | http_redirect_state = STATE_WARNING; | ||
| 736 | if ( !strcmp( optarg, "critical" ) ) | ||
| 737 | http_redirect_state = STATE_CRITICAL; | ||
| 738 | break; | ||
| 739 | case 'g': /* onerror (4xx errors) */ | ||
| 740 | if ( !strcmp( optarg, "unknown" ) ) | ||
| 741 | http_client_error_state = STATE_UNKNOWN; | ||
| 742 | if ( !strcmp( optarg, "ok" ) ) | ||
| 743 | http_client_error_state = STATE_OK; | ||
| 744 | if ( !strcmp( optarg, "warning" ) ) | ||
| 745 | http_client_error_state = STATE_WARNING; | ||
| 746 | if ( !strcmp( optarg, "critical" ) ) | ||
| 747 | http_client_error_state = STATE_CRITICAL; | ||
| 748 | break; | ||
| 749 | case 'm': /* min */ | ||
| 750 | if ( !is_intnonneg( optarg ) ) | ||
| 751 | usage2( "invalid page size", optarg ); | ||
| 752 | min_content_length = atoi( optarg ); | ||
| 753 | use_min_content_length = TRUE; | ||
| 754 | break; | ||
| 755 | } // end switch | ||
| 756 | } // end while(1) | ||
| 757 | |||
| 758 | c = optind; | ||
| 759 | |||
| 760 | |||
| 761 | /* Sanity checks on supplied command line arguments */ | ||
| 762 | |||
| 763 | /* 1. if both host and hostname are not defined, try to | ||
| 764 | * fetch one more argument which is possibly supplied | ||
| 765 | * without an option | ||
| 766 | */ | ||
| 767 | if ( ( strcmp( server_host, "" ) ) && (c < argc) ) { | ||
| 768 | xasprintf( &server_host, "%s", argv[c++] ); | ||
| 769 | } | ||
| 770 | |||
| 771 | /* 2. check if another artument is supplied | ||
| 772 | */ | ||
| 773 | if ( ( strcmp( server_hostname, "" ) == 0 ) && (c < argc) ) { | ||
| 774 | xasprintf( &server_hostname, "%s", argv[c++] ); | ||
| 775 | } | ||
| 776 | |||
| 777 | /* 3. if host is still not defined, just copy hostname, | ||
| 778 | * which is then guaranteed to be defined by now | ||
| 779 | */ | ||
| 780 | if ( strcmp( server_host, "") == 0 ) { | ||
| 781 | if ( strcmp( server_hostname, "" ) == 0 ) { | ||
| 782 | usage ("check_http: you must specify a server address or host name\n"); | ||
| 783 | } else { | ||
| 784 | xasprintf( &server_host, "%s", server_hostname ); | ||
| 785 | } | ||
| 786 | } | ||
| 787 | |||
| 788 | /* 4. check if content checks for a string and a regex | ||
| 789 | * are requested for only one of both is possible at | ||
| 790 | * a time | ||
| 791 | */ | ||
| 792 | if ( check_content_string && check_content_regex ) | ||
| 793 | usage( "check_http: you can only check for string OR regex at a time\n" ); | ||
| 794 | |||
| 795 | /* 5. check for options which require use_ssl */ | ||
| 796 | if ( check_server_certificate && !use_ssl ) | ||
| 797 | usage( "check_http: you must use -S to check server certificate\n" ); | ||
| 798 | if ( use_client_certificate && !use_ssl ) | ||
| 799 | usage( "check_http: you must use -S to authenticate with a client certificate\n" ); | ||
| 800 | if ( use_ca_certificate && !use_ssl ) | ||
| 801 | usage( "check_http: you must use -S to check server certificate against CA certificates\n" ); | ||
| 802 | |||
| 803 | /* 6. check for passphrase without client certificate */ | ||
| 804 | if ( use_client_certificate_passphrase && !use_client_certificate ) | ||
| 805 | usage( "check_http: you must supply a client certificate to use a passphrase\n" ); | ||
| 806 | |||
| 807 | |||
| 808 | /* Finally set some default values if necessary */ | ||
| 809 | if ( strcmp( http_method, "" ) == 0 ) | ||
| 810 | xasprintf( &http_method, "%s", DEFAULT_HTTP_METHOD ); | ||
| 811 | if ( strcmp( http_url_path, "" ) == 0 ) { | ||
| 812 | xasprintf( &http_url_path, "%s", DEFAULT_HTTP_URL_PATH ); | ||
| 813 | } | ||
| 814 | |||
| 815 | return TRUE; | ||
| 816 | } | ||
| 817 | |||
| 818 | |||
| 819 | int | ||
| 820 | http_request( int sock, struct pageref *page ) | ||
| 821 | { | ||
| 822 | char *buffer = ""; | ||
| 823 | char recvbuff[MAX_INPUT_BUFFER] = ""; | ||
| 824 | int buffer_len = 0; | ||
| 825 | int content_len = 0; | ||
| 826 | size_t sendsize = 0; | ||
| 827 | size_t recvsize = 0; | ||
| 828 | char *content = ""; | ||
| 829 | size_t size = 0; | ||
| 830 | char *basic_auth_encoded = NULL; | ||
| 831 | |||
| 832 | xasprintf( &buffer, HTTP_TEMPLATE_REQUEST, buffer, http_method, http_url_path ); | ||
| 833 | |||
| 834 | xasprintf( &buffer, HTTP_TEMPLATE_HEADER_USERAGENT, buffer, progname, REVISION, PACKAGE_VERSION ); | ||
| 835 | |||
| 836 | if ( use_server_hostname ) { | ||
| 837 | xasprintf( &buffer, HTTP_TEMPLATE_HEADER_HOST, buffer, server_hostname ); | ||
| 838 | } | ||
| 839 | |||
| 840 | if ( use_basic_auth ) { | ||
| 841 | basic_auth_encoded = base64( basic_auth, strlen( basic_auth ) ); | ||
| 842 | xasprintf( &buffer, HTTP_TEMPLATE_HEADER_AUTH, buffer, basic_auth_encoded ); | ||
| 843 | } | ||
| 844 | |||
| 845 | /* either send http POST data */ | ||
| 846 | if ( use_http_post_data ) { | ||
| 847 | /* based on code written by Chris Henesy <lurker@shadowtech.org> */ | ||
| 848 | xasprintf( &buffer, "Content-Type: application/x-www-form-urlencoded\r\n" ); | ||
| 849 | xasprintf( &buffer, "Content-Length: %i\r\n\r\n", buffer, content_len ); | ||
| 850 | xasprintf( &buffer, "%s%s%s", buffer, http_post_data, "\r\n" ); | ||
| 851 | sendsize = send( sock, buffer, strlen( buffer ), 0 ); | ||
| 852 | if ( sendsize < strlen( buffer ) ) { | ||
| 853 | printf( "ERROR: Incomplete write\n" ); | ||
| 854 | return STATE_CRITICAL; | ||
| 855 | } | ||
| 856 | /* or just a newline */ | ||
| 857 | } else { | ||
| 858 | xasprintf( &buffer, "%s%s", buffer, "\r\n" ); | ||
| 859 | sendsize = send( sock, buffer, strlen( buffer ) , 0 ); | ||
| 860 | if ( sendsize < strlen( buffer ) ) { | ||
| 861 | printf( "ERROR: Incomplete write\n" ); | ||
| 862 | return STATE_CRITICAL; | ||
| 863 | } | ||
| 864 | } | ||
| 865 | |||
| 866 | |||
| 867 | /* read server's response */ | ||
| 868 | |||
| 869 | do { | ||
| 870 | recvsize = recv( sock, recvbuff, MAX_INPUT_BUFFER - 1, 0 ); | ||
| 871 | if ( recvsize > (size_t) 0 ) { | ||
| 872 | recvbuff[recvsize] = '\0'; | ||
| 873 | xasprintf( &content, "%s%s", content, recvbuff ); | ||
| 874 | size += recvsize; | ||
| 875 | } | ||
| 876 | } while ( recvsize > (size_t) 0 ); | ||
| 877 | |||
| 878 | xasprintf( &page->content, "%s", content ); | ||
| 879 | page->size = size; | ||
| 880 | |||
| 881 | /* return a CRITICAL status if we couldn't read any data */ | ||
| 882 | if ( size == (size_t) 0) | ||
| 883 | ssl_terminate( STATE_CRITICAL, "No data received" ); | ||
| 884 | |||
| 885 | return STATE_OK; | ||
| 886 | } | ||
| 887 | |||
| 888 | |||
| 889 | int | ||
| 890 | parse_http_response( struct pageref *page ) | ||
| 891 | { | ||
| 892 | char *content = ""; //local copy of struct member | ||
| 893 | char *status = ""; //local copy of struct member | ||
| 894 | char *header = ""; //local copy of struct member | ||
| 895 | size_t len = 0; //temporary used | ||
| 896 | char *pos = ""; //temporary used | ||
| 897 | |||
| 898 | xasprintf( &content, "%s", page->content ); | ||
| 899 | |||
| 900 | /* find status line and null-terminate it */ | ||
| 901 | // copy content to status | ||
| 902 | status = content; | ||
| 903 | |||
| 904 | // find end of status line and copy pointer to pos | ||
| 905 | content += (size_t) strcspn( content, "\r\n" ); | ||
| 906 | pos = content; | ||
| 907 | |||
| 908 | // advance content pointer behind the newline of status line | ||
| 909 | content += (size_t) strspn( content, "\r\n" ); | ||
| 910 | |||
| 911 | // null-terminate status line at pos | ||
| 912 | status[strcspn( status, "\r\n")] = 0; | ||
| 913 | strip( status ); | ||
| 914 | |||
| 915 | // copy final status to struct member | ||
| 916 | page->status = status; | ||
| 917 | |||
| 918 | |||
| 919 | /* find header and null-terminate it */ | ||
| 920 | // copy remaining content to header | ||
| 921 | header = content; | ||
| 922 | |||
| 923 | // loop until line containing only newline is found (end of header) | ||
| 924 | while ( strcspn( content, "\r\n" ) > 0 ) { | ||
| 925 | //find end of line and copy pointer to pos | ||
| 926 | content += (size_t) strcspn( content, "\r\n" ); | ||
| 927 | pos = content; | ||
| 928 | |||
| 929 | if ( ( strspn( content, "\r" ) == 1 && strspn( content, "\r\n" ) >= 2 ) || | ||
| 930 | ( strspn( content, "\n" ) == 1 && strspn( content, "\r\n" ) >= 2 ) ) | ||
| 931 | content += (size_t) 2; | ||
| 932 | else | ||
| 933 | content += (size_t) 1; | ||
| 934 | } | ||
| 935 | // advance content pointer behind the newline | ||
| 936 | content += (size_t) strspn( content, "\r\n" ); | ||
| 937 | |||
| 938 | // null-terminate header at pos | ||
| 939 | header[pos - header] = 0; | ||
| 940 | |||
| 941 | // copy final header to struct member | ||
| 942 | page->header = header; | ||
| 943 | |||
| 944 | |||
| 945 | // copy remaining content to body | ||
| 946 | page->body = content; | ||
| 947 | |||
| 948 | if ( verbose ) { | ||
| 949 | printf( "STATUS: %s\n", page->status ); | ||
| 950 | printf( "HEADER: \n%s\n", page->header ); | ||
| 951 | printf( "BODY: \n%s\n", page->body ); | ||
| 952 | } | ||
| 953 | |||
| 954 | return STATE_OK; | ||
| 955 | } | ||
| 956 | |||
| 957 | |||
| 958 | int | ||
| 959 | check_http_response( struct pageref *page ) | ||
| 960 | { | ||
| 961 | char *msg = ""; | ||
| 962 | |||
| 963 | /* check response time befor anything else */ | ||
| 964 | if ( use_critical_interval && ( elapsed_time > critical_interval ) ) { | ||
| 965 | xasprintf( &msg, RESULT_TEMPLATE_RESPONSE_TIME, | ||
| 966 | protocol_text( use_ssl ), | ||
| 967 | state_text( STATE_CRITICAL ), | ||
| 968 | elapsed_time, | ||
| 969 | elapsed_time ); | ||
| 970 | terminate( STATE_CRITICAL, msg ); | ||
| 971 | } | ||
| 972 | if ( use_warning_interval && ( elapsed_time > warning_interval ) ) { | ||
| 973 | xasprintf( &msg, RESULT_TEMPLATE_RESPONSE_TIME, | ||
| 974 | protocol_text( use_ssl ), | ||
| 975 | state_text( STATE_WARNING ), | ||
| 976 | elapsed_time, | ||
| 977 | elapsed_time ); | ||
| 978 | terminate( STATE_WARNING, msg ); | ||
| 979 | } | ||
| 980 | |||
| 981 | |||
| 982 | /* make sure the status line matches the response we are looking for */ | ||
| 983 | if ( strstr( page->status, http_expect ) ) { | ||
| 984 | /* The result is only checked against the expected HTTP status line, | ||
| 985 | so exit immediately after this check */ | ||
| 986 | if ( use_http_expect_only ) { | ||
| 987 | if ( ( server_port == HTTP_PORT ) | ||
| 988 | #ifdef HAVE_SSL | ||
| 989 | || ( server_port == HTTPS_PORT ) ) | ||
| 990 | #else | ||
| 991 | ) | ||
| 992 | #endif | ||
| 993 | xasprintf( &msg, "Expected HTTP response received from host\n" ); | ||
| 994 | else | ||
| 995 | xasprintf( &msg, "Expected HTTP response received from host on port %d\n", server_port ); | ||
| 996 | terminate( STATE_OK, msg ); | ||
| 997 | } | ||
| 998 | } else { | ||
| 999 | if ( ( server_port == HTTP_PORT ) | ||
| 1000 | #ifdef HAVE_SSL | ||
| 1001 | || ( server_port == HTTPS_PORT ) ) | ||
| 1002 | #else | ||
| 1003 | ) | ||
| 1004 | #endif | ||
| 1005 | xasprintf( &msg, "Invalid HTTP response received from host\n" ); | ||
| 1006 | else | ||
| 1007 | xasprintf( &msg, "Invalid HTTP response received from host on port %d\n", server_port ); | ||
| 1008 | terminate( STATE_CRITICAL, msg ); | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | /* check the return code */ | ||
| 1012 | /* server errors result in a critical state */ | ||
| 1013 | if ( strstr( page->status, "500" ) || | ||
| 1014 | strstr( page->status, "501" ) || | ||
| 1015 | strstr( page->status, "502" ) || | ||
| 1016 | strstr( page->status, "503" ) || | ||
| 1017 | strstr( page->status, "504" ) || | ||
| 1018 | strstr( page->status, "505" )) { | ||
| 1019 | xasprintf( &msg, RESULT_TEMPLATE_STATUS_RESPONSE_TIME, | ||
| 1020 | protocol_text( use_ssl ), | ||
| 1021 | state_text( http_client_error_state ), | ||
| 1022 | page->status, | ||
| 1023 | elapsed_time, | ||
| 1024 | elapsed_time ); | ||
| 1025 | terminate( STATE_CRITICAL, msg ); | ||
| 1026 | } | ||
| 1027 | |||
| 1028 | /* client errors result in a warning state */ | ||
| 1029 | if ( strstr( page->status, "400" ) || | ||
| 1030 | strstr( page->status, "401" ) || | ||
| 1031 | strstr( page->status, "402" ) || | ||
| 1032 | strstr( page->status, "403" ) || | ||
| 1033 | strstr( page->status, "404" ) || | ||
| 1034 | strstr( page->status, "405" ) || | ||
| 1035 | strstr( page->status, "406" ) || | ||
| 1036 | strstr( page->status, "407" ) || | ||
| 1037 | strstr( page->status, "408" ) || | ||
| 1038 | strstr( page->status, "409" ) || | ||
| 1039 | strstr( page->status, "410" ) || | ||
| 1040 | strstr( page->status, "411" ) || | ||
| 1041 | strstr( page->status, "412" ) || | ||
| 1042 | strstr( page->status, "413" ) || | ||
| 1043 | strstr( page->status, "414" ) || | ||
| 1044 | strstr( page->status, "415" ) || | ||
| 1045 | strstr( page->status, "416" ) || | ||
| 1046 | strstr( page->status, "417" ) ) { | ||
| 1047 | xasprintf( &msg, RESULT_TEMPLATE_STATUS_RESPONSE_TIME, | ||
| 1048 | protocol_text( use_ssl ), | ||
| 1049 | state_text( http_client_error_state ), | ||
| 1050 | page->status, | ||
| 1051 | elapsed_time, | ||
| 1052 | elapsed_time ); | ||
| 1053 | terminate( http_client_error_state, msg ); | ||
| 1054 | } | ||
| 1055 | |||
| 1056 | /* check redirected page if specified */ | ||
| 1057 | if (strstr( page->status, "300" ) || | ||
| 1058 | strstr( page->status, "301" ) || | ||
| 1059 | strstr( page->status, "302" ) || | ||
| 1060 | strstr( page->status, "303" ) || | ||
| 1061 | strstr( page->status, "304" ) || | ||
| 1062 | strstr( page->status, "305" ) || | ||
| 1063 | strstr( page->status, "306" ) || | ||
| 1064 | strstr( page->status, "307" ) ) { | ||
| 1065 | if ( http_redirect_state == STATE_DEPENDENT ) { | ||
| 1066 | /* returning STATE_DEPENDENT means follow redirect */ | ||
| 1067 | return STATE_DEPENDENT; | ||
| 1068 | } else { | ||
| 1069 | xasprintf( &msg, RESULT_TEMPLATE_STATUS_RESPONSE_TIME, | ||
| 1070 | protocol_text( use_ssl ), | ||
| 1071 | state_text( http_redirect_state ), | ||
| 1072 | page->status, | ||
| 1073 | elapsed_time, | ||
| 1074 | elapsed_time ); | ||
| 1075 | terminate( http_redirect_state, msg ); | ||
| 1076 | } | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | return STATE_OK; | ||
| 1080 | } | ||
| 1081 | |||
| 1082 | int | ||
| 1083 | check_http_content( struct pageref *page ) | ||
| 1084 | { | ||
| 1085 | char *msg = ""; | ||
| 1086 | |||
| 1087 | /* check for string in content */ | ||
| 1088 | if ( check_content_string ) { | ||
| 1089 | if ( strstr( page->content, content_string ) ) { | ||
| 1090 | xasprintf( &msg, RESULT_TEMPLATE_STATUS_RESPONSE_TIME, | ||
| 1091 | protocol_text( use_ssl ), | ||
| 1092 | state_text( STATE_OK ), | ||
| 1093 | page->status, | ||
| 1094 | elapsed_time, | ||
| 1095 | elapsed_time ); | ||
| 1096 | terminate( STATE_OK, msg ); | ||
| 1097 | } else { | ||
| 1098 | xasprintf( &msg, RESULT_TEMPLATE_STATUS_RESPONSE_TIME, | ||
| 1099 | protocol_text( use_ssl ), | ||
| 1100 | state_text( STATE_CRITICAL ), | ||
| 1101 | page->status, | ||
| 1102 | elapsed_time, | ||
| 1103 | elapsed_time ); | ||
| 1104 | terminate( STATE_CRITICAL, msg ); | ||
| 1105 | } | ||
| 1106 | } | ||
| 1107 | |||
| 1108 | #ifdef HAVE_REGEX_H | ||
| 1109 | /* check for regex in content */ | ||
| 1110 | if ( check_content_regex ) { | ||
| 1111 | regex_error = regexec( ®ex_preg, page->content, REGEX_REGS, regex_pmatch, 0); | ||
| 1112 | if ( regex_error == 0 ) { | ||
| 1113 | xasprintf( &msg, RESULT_TEMPLATE_STATUS_RESPONSE_TIME, | ||
| 1114 | protocol_text( use_ssl ), | ||
| 1115 | state_text( STATE_OK ), | ||
| 1116 | page->status, | ||
| 1117 | elapsed_time, | ||
| 1118 | elapsed_time ); | ||
| 1119 | terminate( STATE_OK, msg ); | ||
| 1120 | } else { | ||
| 1121 | if ( regex_error == REG_NOMATCH ) { | ||
| 1122 | xasprintf( &msg, "%s, %s: regex pattern not found\n", | ||
| 1123 | protocol_text( use_ssl) , | ||
| 1124 | state_text( STATE_CRITICAL ) ); | ||
| 1125 | terminate( STATE_CRITICAL, msg ); | ||
| 1126 | } else { | ||
| 1127 | regerror( regex_error, ®ex_preg, regex_error_buffer, MAX_INPUT_BUFFER); | ||
| 1128 | xasprintf( &msg, "%s %s: Regex execute Error: %s\n", | ||
| 1129 | protocol_text( use_ssl) , | ||
| 1130 | state_text( STATE_CRITICAL ), | ||
| 1131 | regex_error_buffer ); | ||
| 1132 | terminate( STATE_CRITICAL, msg ); | ||
| 1133 | } | ||
| 1134 | } | ||
| 1135 | } | ||
| 1136 | #endif | ||
| 1137 | |||
| 1138 | return STATE_OK; | ||
| 1139 | } | ||
| 1140 | |||
| 1141 | |||
| 1142 | int | ||
| 1143 | prepare_follow_redirect( struct pageref *page ) | ||
| 1144 | { | ||
| 1145 | char *header = NULL; | ||
| 1146 | char *msg = ""; | ||
| 1147 | char protocol[6]; | ||
| 1148 | char hostname[MAX_IPV4_HOSTLENGTH]; | ||
| 1149 | char port[6]; | ||
| 1150 | char *url_path = NULL; | ||
| 1151 | char *orig_url_path = NULL; | ||
| 1152 | char *orig_url_dirname = NULL; | ||
| 1153 | size_t len = 0; | ||
| 1154 | |||
| 1155 | xasprintf( &header, "%s", page->header ); | ||
| 1156 | |||
| 1157 | |||
| 1158 | /* restore some default values */ | ||
| 1159 | use_http_post_data = FALSE; | ||
| 1160 | xasprintf( &http_method, "%s", DEFAULT_HTTP_METHOD ); | ||
| 1161 | |||
| 1162 | /* copy url of original request, maybe we need it to compose | ||
| 1163 | absolute url from relative Location: header */ | ||
| 1164 | xasprintf( &orig_url_path, "%s", http_url_path ); | ||
| 1165 | |||
| 1166 | while ( strcspn( header, "\r\n" ) > (size_t) 0 ) { | ||
| 1167 | url_path = realloc( url_path, (size_t) strcspn( header, "\r\n" ) ); | ||
| 1168 | if ( url_path == NULL ) | ||
| 1169 | terminate( STATE_UNKNOWN, "HTTP UNKNOWN: could not reallocate url_path" ); | ||
| 1170 | |||
| 1171 | |||
| 1172 | /* Try to find a Location header combination of METHOD HOSTNAME PORT and PATH */ | ||
| 1173 | /* 1. scan for Location: http[s]://hostname:port/path */ | ||
| 1174 | if ( sscanf ( header, HTTP_HEADER_LOCATION_MATCH HTTP_HEADER_PROTOCOL_MATCH HTTP_HEADER_HOSTNAME_MATCH HTTP_HEADER_PORT_MATCH HTTP_HEADER_URL_PATH_MATCH, &protocol, &hostname, &port, url_path ) == 4 ) { | ||
| 1175 | xasprintf( &server_hostname, "%s", hostname ); | ||
| 1176 | xasprintf( &server_host, "%s", hostname ); | ||
| 1177 | use_ssl = chk_protocol(protocol); | ||
| 1178 | server_port = atoi( port ); | ||
| 1179 | xasprintf( &http_url_path, "%s", url_path ); | ||
| 1180 | return STATE_DEPENDENT; | ||
| 1181 | } | ||
| 1182 | else if ( sscanf ( header, HTTP_HEADER_LOCATION_MATCH HTTP_HEADER_PROTOCOL_MATCH HTTP_HEADER_HOSTNAME_MATCH HTTP_HEADER_URL_PATH_MATCH, &protocol, &hostname, url_path ) == 3) { | ||
| 1183 | xasprintf( &server_hostname, "%s", hostname ); | ||
| 1184 | xasprintf( &server_host, "%s", hostname ); | ||
| 1185 | use_ssl = chk_protocol(protocol); | ||
| 1186 | server_port = protocol_std_port(use_ssl); | ||
| 1187 | xasprintf( &http_url_path, "%s", url_path ); | ||
| 1188 | return STATE_DEPENDENT; | ||
| 1189 | } | ||
| 1190 | else if ( sscanf ( header, HTTP_HEADER_LOCATION_MATCH HTTP_HEADER_PROTOCOL_MATCH HTTP_HEADER_HOSTNAME_MATCH HTTP_HEADER_PORT_MATCH, &protocol, &hostname, &port ) == 3) { | ||
| 1191 | xasprintf( &server_hostname, "%s", hostname ); | ||
| 1192 | xasprintf( &server_host, "%s", hostname ); | ||
| 1193 | use_ssl = chk_protocol(protocol); | ||
| 1194 | server_port = atoi( port ); | ||
| 1195 | xasprintf( &http_url_path, "%s", DEFAULT_HTTP_URL_PATH ); | ||
| 1196 | return STATE_DEPENDENT; | ||
| 1197 | } | ||
| 1198 | else if ( sscanf ( header, HTTP_HEADER_LOCATION_MATCH HTTP_HEADER_PROTOCOL_MATCH HTTP_HEADER_HOSTNAME_MATCH, protocol, hostname ) == 2 ) { | ||
| 1199 | xasprintf( &server_hostname, "%s", hostname ); | ||
| 1200 | xasprintf( &server_host, "%s", hostname ); | ||
| 1201 | use_ssl = chk_protocol(protocol); | ||
| 1202 | server_port = protocol_std_port(use_ssl); | ||
| 1203 | xasprintf( &http_url_path, "%s", DEFAULT_HTTP_URL_PATH ); | ||
| 1204 | } | ||
| 1205 | else if ( sscanf ( header, HTTP_HEADER_LOCATION_MATCH HTTP_HEADER_URL_PATH_MATCH, url_path ) == 1 ) { | ||
| 1206 | /* check for relative url and prepend path if necessary */ | ||
| 1207 | if ( ( url_path[0] != '/' ) && ( orig_url_dirname = strrchr( orig_url_path, '/' ) ) ) { | ||
| 1208 | *orig_url_dirname = '\0'; | ||
| 1209 | xasprintf( &http_url_path, "%s%s", orig_url_path, url_path ); | ||
| 1210 | } else { | ||
| 1211 | xasprintf( &http_url_path, "%s", url_path ); | ||
| 1212 | } | ||
| 1213 | return STATE_DEPENDENT; | ||
| 1214 | } | ||
| 1215 | header += (size_t) strcspn( header, "\r\n" ); | ||
| 1216 | header += (size_t) strspn( header, "\r\n" ); | ||
| 1217 | } /* end while (header) */ | ||
| 1218 | |||
| 1219 | |||
| 1220 | /* default return value is STATE_DEPENDENT to continue looping in main() */ | ||
| 1221 | xasprintf( &msg, "% %: % - Could not find redirect Location", | ||
| 1222 | protocol_text( use_ssl ), | ||
| 1223 | state_text( STATE_UNKNOWN ), | ||
| 1224 | page->status ); | ||
| 1225 | terminate( STATE_UNKNOWN, msg ); | ||
| 1226 | } | ||
| 1227 | |||
| 1228 | #ifdef HAVE_SSL | ||
| 1229 | int | ||
| 1230 | https_request( SSL_CTX *ctx, SSL *ssl, struct pageref *page ) | ||
| 1231 | { | ||
| 1232 | char *buffer = ""; | ||
| 1233 | char recvbuff[MAX_INPUT_BUFFER] = ""; | ||
| 1234 | int buffer_len = 0; | ||
| 1235 | int content_len = 0; | ||
| 1236 | size_t sendsize = 0; | ||
| 1237 | size_t recvsize = 0; | ||
| 1238 | char *content = ""; | ||
| 1239 | size_t size = 0; | ||
| 1240 | char *basic_auth_encoded = NULL; | ||
| 1241 | |||
| 1242 | xasprintf( &buffer, HTTP_TEMPLATE_REQUEST, buffer, http_method, http_url_path ); | ||
| 1243 | |||
| 1244 | xasprintf( &buffer, HTTP_TEMPLATE_HEADER_USERAGENT, buffer, progname, REVISION, PACKAGE_VERSION ); | ||
| 1245 | |||
| 1246 | if ( use_server_hostname ) { | ||
| 1247 | xasprintf( &buffer, HTTP_TEMPLATE_HEADER_HOST, buffer, server_hostname ); | ||
| 1248 | } | ||
| 1249 | |||
| 1250 | if ( use_basic_auth ) { | ||
| 1251 | basic_auth_encoded = base64( basic_auth, strlen( basic_auth ) ); | ||
| 1252 | xasprintf( &buffer, HTTP_TEMPLATE_HEADER_AUTH, buffer, basic_auth_encoded ); | ||
| 1253 | } | ||
| 1254 | |||
| 1255 | /* either send http POST data */ | ||
| 1256 | if ( use_http_post_data ) { | ||
| 1257 | xasprintf( &buffer, "%sContent-Type: application/x-www-form-urlencoded\r\n", buffer ); | ||
| 1258 | xasprintf( &buffer, "%sContent-Length: %i\r\n\r\n", buffer, content_len ); | ||
| 1259 | xasprintf( &buffer, "%s%s%s", buffer, http_post_data, "\r\n" ); | ||
| 1260 | sendsize = SSL_write( ssl, buffer, strlen( buffer ) ); | ||
| 1261 | switch ( SSL_get_error( ssl, sendsize ) ) { | ||
| 1262 | case SSL_ERROR_NONE: | ||
| 1263 | if ( sendsize < strlen( buffer ) ) | ||
| 1264 | ssl_terminate( STATE_CRITICAL, "SSL ERROR: Incomplete write.\n" ); | ||
| 1265 | break; | ||
| 1266 | default: | ||
| 1267 | ssl_terminate( STATE_CRITICAL, "SSL ERROR: Write problem.\n" ); | ||
| 1268 | break; | ||
| 1269 | } | ||
| 1270 | /* or just a newline */ | ||
| 1271 | } else { | ||
| 1272 | |||
| 1273 | xasprintf( &buffer, "%s\r\n", buffer ); | ||
| 1274 | sendsize = SSL_write( ssl, buffer, strlen( buffer ) ); | ||
| 1275 | switch ( SSL_get_error( ssl, sendsize ) ) { | ||
| 1276 | case SSL_ERROR_NONE: | ||
| 1277 | if ( sendsize < strlen( buffer ) ) | ||
| 1278 | ssl_terminate( STATE_CRITICAL, "SSL ERROR: Incomplete write.\n" ); | ||
| 1279 | break; | ||
| 1280 | default: | ||
| 1281 | ssl_terminate( STATE_CRITICAL, "SSL ERROR: Write problem.\n" ); | ||
| 1282 | break; | ||
| 1283 | } | ||
| 1284 | } | ||
| 1285 | |||
| 1286 | |||
| 1287 | /* read server's response */ | ||
| 1288 | |||
| 1289 | do { | ||
| 1290 | recvsize = SSL_read( ssl, recvbuff, MAX_INPUT_BUFFER - 1 ); | ||
| 1291 | |||
| 1292 | switch ( SSL_get_error( ssl, recvsize ) ) { | ||
| 1293 | case SSL_ERROR_NONE: | ||
| 1294 | if ( recvsize > (size_t) 0 ) { | ||
| 1295 | recvbuff[recvsize] = '\0'; | ||
| 1296 | xasprintf( &content, "%s%s", content, recvbuff ); | ||
| 1297 | size += recvsize; | ||
| 1298 | } | ||
| 1299 | break; | ||
| 1300 | case SSL_ERROR_WANT_READ: | ||
| 1301 | if ( use_client_certificate ) { | ||
| 1302 | continue; | ||
| 1303 | } else { | ||
| 1304 | // workaround while we don't have anonymous client certificates: return OK | ||
| 1305 | //ssl_terminate( STATE_WARNING, "HTTPS WARNING - Client Certificate required.\n" ); | ||
| 1306 | ssl_terminate( STATE_OK, "HTTPS WARNING - Client Certificate required.\n" ); | ||
| 1307 | } | ||
| 1308 | break; | ||
| 1309 | case SSL_ERROR_ZERO_RETURN: | ||
| 1310 | break; | ||
| 1311 | case SSL_ERROR_SYSCALL: | ||
| 1312 | ssl_terminate( STATE_CRITICAL, "SSL ERROR: Premature close.\n" ); | ||
| 1313 | break; | ||
| 1314 | default: | ||
| 1315 | ssl_terminate( STATE_CRITICAL, "SSL ERROR: Read problem.\n" ); | ||
| 1316 | break; | ||
| 1317 | } | ||
| 1318 | } while ( recvsize > (size_t) 0 ); | ||
| 1319 | |||
| 1320 | xasprintf( &page->content, "%s", content ); | ||
| 1321 | page->size = size; | ||
| 1322 | |||
| 1323 | /* return a CRITICAL status if we couldn't read any data */ | ||
| 1324 | if ( size == (size_t) 0) | ||
| 1325 | ssl_terminate( STATE_CRITICAL, "No data received" ); | ||
| 1326 | |||
| 1327 | return STATE_OK; | ||
| 1328 | } | ||
| 1329 | #endif | ||
| 1330 | |||
| 1331 | |||
| 1332 | #ifdef HAVE_SSL | ||
| 1333 | int | ||
| 1334 | ssl_terminate(int state, char *string ) { | ||
| 1335 | ERR_print_errors( bio_err ); | ||
| 1336 | terminate( state, string ); | ||
| 1337 | } | ||
| 1338 | #endif | ||
| 1339 | |||
| 1340 | #ifdef HAVE_SSL | ||
| 1341 | static int | ||
| 1342 | password_cb( char *buf, int num, int rwflag, void *userdata ) | ||
| 1343 | { | ||
| 1344 | if ( num < strlen( client_certificate_passphrase ) + 1 ) | ||
| 1345 | return( 0 ); | ||
| 1346 | |||
| 1347 | strcpy( buf, client_certificate_passphrase ); | ||
| 1348 | return( strlen( client_certificate_passphrase ) ); | ||
| 1349 | } | ||
| 1350 | #endif | ||
| 1351 | |||
| 1352 | #ifdef HAVE_SSL | ||
| 1353 | static void | ||
| 1354 | sigpipe_handle( int x ) { | ||
| 1355 | } | ||
| 1356 | #endif | ||
| 1357 | |||
| 1358 | #ifdef HAVE_SSL | ||
| 1359 | SSL_CTX * | ||
| 1360 | initialize_ssl_ctx( void ) | ||
| 1361 | { | ||
| 1362 | SSL_METHOD *meth; | ||
| 1363 | SSL_CTX *ctx; | ||
| 1364 | |||
| 1365 | if ( !bio_err ) { | ||
| 1366 | /* Global system initialization */ | ||
| 1367 | SSL_library_init(); | ||
| 1368 | SSL_load_error_strings(); | ||
| 1369 | |||
| 1370 | /* An error write context */ | ||
| 1371 | bio_err=BIO_new_fp( stderr, BIO_NOCLOSE ); | ||
| 1372 | } | ||
| 1373 | |||
| 1374 | /* set up as SIGPIPE handler */ | ||
| 1375 | signal( SIGPIPE, sigpipe_handle ); | ||
| 1376 | |||
| 1377 | /* create our context */ | ||
| 1378 | meth=SSLv3_method(); | ||
| 1379 | ctx=SSL_CTX_new( meth ); | ||
| 1380 | |||
| 1381 | /* load client certificate and key */ | ||
| 1382 | if ( use_client_certificate ) { | ||
| 1383 | if ( !(SSL_CTX_use_certificate_chain_file( ctx, client_certificate_file )) ) | ||
| 1384 | ssl_terminate( STATE_CRITICAL, "check_http: can't read client certificate file" ); | ||
| 1385 | |||
| 1386 | /* set client certificate key passphrase */ | ||
| 1387 | if ( use_client_certificate_passphrase ) { | ||
| 1388 | SSL_CTX_set_default_passwd_cb( ctx, password_cb ); | ||
| 1389 | } | ||
| 1390 | |||
| 1391 | if ( !(SSL_CTX_use_PrivateKey_file( ctx, client_certificate_file, SSL_FILETYPE_PEM )) ) | ||
| 1392 | ssl_terminate( STATE_CRITICAL, "check_http: can't read client certificate key file" ); | ||
| 1393 | } | ||
| 1394 | |||
| 1395 | /* load the CAs we trust */ | ||
| 1396 | if ( use_ca_certificate ) { | ||
| 1397 | if ( !(SSL_CTX_load_verify_locations( ctx, ca_certificate_file, 0 )) ) | ||
| 1398 | ssl_terminate( STATE_CRITICAL, "check_http: can't read CA certificate file" ); | ||
| 1399 | |||
| 1400 | #if (OPENSSL_VERSION_NUMBER < 0x00905100L) | ||
| 1401 | SSL_CTX_set_verify_depth( ctx, 1 ); | ||
| 1402 | #endif | ||
| 1403 | } | ||
| 1404 | |||
| 1405 | return ctx; | ||
| 1406 | } | ||
| 1407 | #endif | ||
| 1408 | |||
| 1409 | #ifdef HAVE_SSL | ||
| 1410 | void destroy_ssl_ctx( SSL_CTX *ctx ) | ||
| 1411 | { | ||
| 1412 | SSL_CTX_free( ctx ); | ||
| 1413 | } | ||
| 1414 | #endif | ||
| 1415 | |||
| 1416 | #ifdef HAVE_SSL | ||
| 1417 | int | ||
| 1418 | fetch_server_certificate( SSL *ssl ) | ||
| 1419 | { | ||
| 1420 | server_certificate = SSL_get_peer_certificate( ssl ); | ||
| 1421 | if ( server_certificate == NULL ) | ||
| 1422 | ssl_terminate( STATE_CRITICAL, "SSL ERROR: Cannot retrieve server certificate.\n" ); | ||
| 1423 | |||
| 1424 | return STATE_OK; | ||
| 1425 | } | ||
| 1426 | #endif | ||
| 1427 | |||
| 1428 | |||
| 1429 | #ifdef HAVE_SSL | ||
| 1430 | int | ||
| 1431 | check_server_certificate_chain( SSL *ssl ) | ||
| 1432 | { | ||
| 1433 | if ( SSL_get_verify_result( ssl ) != X509_V_OK ) | ||
| 1434 | ssl_terminate( STATE_CRITICAL, "SSL ERROR: Cannot verify server certificate chain.\n" ); | ||
| 1435 | |||
| 1436 | return STATE_OK; | ||
| 1437 | } | ||
| 1438 | #endif | ||
| 1439 | |||
| 1440 | |||
| 1441 | #ifdef HAVE_SSL | ||
| 1442 | int | ||
| 1443 | check_server_certificate_hostname( ) | ||
| 1444 | { | ||
| 1445 | char server_CN[256]; | ||
| 1446 | char *msg = NULL; | ||
| 1447 | X509_NAME_get_text_by_NID( X509_get_subject_name( server_certificate ), NID_commonName, server_CN, 256 ); | ||
| 1448 | if ( strcasecmp( server_CN, server_hostname ) ) { | ||
| 1449 | xasprintf( &msg, "SSL ERROR: Server Certificate does not match Hostname %s.\n", server_hostname ); | ||
| 1450 | ssl_terminate( STATE_WARNING, msg ); | ||
| 1451 | } | ||
| 1452 | |||
| 1453 | return STATE_OK; | ||
| 1454 | } | ||
| 1455 | #endif | ||
| 1456 | |||
| 1457 | #ifdef HAVE_SSL | ||
| 1458 | int | ||
| 1459 | check_server_certificate_expires( ) | ||
| 1460 | { | ||
| 1461 | ASN1_STRING *tm; | ||
| 1462 | int offset; | ||
| 1463 | struct tm stamp; | ||
| 1464 | int days_left; | ||
| 1465 | char timestamp[17] = ""; | ||
| 1466 | char *msg = NULL; | ||
| 1467 | |||
| 1468 | /* Retrieve timestamp of certificate */ | ||
| 1469 | tm = X509_get_notAfter( server_certificate ); | ||
| 1470 | |||
| 1471 | /* Generate tm structure to process timestamp */ | ||
| 1472 | if ( tm->type == V_ASN1_UTCTIME ) { | ||
| 1473 | if ( tm->length < 10 ) { | ||
| 1474 | ssl_terminate( STATE_CRITICAL, "ERROR: Wrong time format in certificate.\n" ); | ||
| 1475 | } else { | ||
| 1476 | stamp.tm_year = ( tm->data[0] - '0' ) * 10 + ( tm->data[1] - '0' ); | ||
| 1477 | if ( stamp.tm_year < 50 ) | ||
| 1478 | stamp.tm_year += 100; | ||
| 1479 | offset = 0; | ||
| 1480 | } | ||
| 1481 | } else { | ||
| 1482 | if ( tm->length < 12 ) { | ||
| 1483 | ssl_terminate( STATE_CRITICAL, "ERROR: Wrong time format in certificate.\n" ); | ||
| 1484 | } else { | ||
| 1485 | stamp.tm_year = | ||
| 1486 | ( tm->data[0] - '0' ) * 1000 + ( tm->data[1] - '0' ) * 100 + | ||
| 1487 | ( tm->data[2] - '0' ) * 10 + ( tm->data[3] - '0' ); | ||
| 1488 | stamp.tm_year -= 1900; | ||
| 1489 | offset = 2; | ||
| 1490 | } | ||
| 1491 | } | ||
| 1492 | stamp.tm_mon = | ||
| 1493 | ( tm->data[2 + offset] - '0' ) * 10 + ( tm->data[3 + offset] - '0' ) - 1; | ||
| 1494 | stamp.tm_mday = | ||
| 1495 | ( tm->data[4 + offset] - '0' ) * 10 + ( tm->data[5 + offset] - '0' ); | ||
| 1496 | stamp.tm_hour = | ||
| 1497 | ( tm->data[6 + offset] - '0' ) * 10 + ( tm->data[7 + offset] - '0' ); | ||
| 1498 | stamp.tm_min = | ||
| 1499 | ( tm->data[8 + offset] - '0' ) * 10 + ( tm->data[9 + offset] - '0' ); | ||
| 1500 | stamp.tm_sec = 0; | ||
| 1501 | stamp.tm_isdst = -1; | ||
| 1502 | |||
| 1503 | days_left = ( mktime( &stamp ) - time( NULL ) ) / 86400; | ||
| 1504 | snprintf | ||
| 1505 | ( timestamp, 17, "%02d.%02d.%04d %02d:%02d", | ||
| 1506 | stamp.tm_mday, stamp.tm_mon +1, stamp.tm_year + 1900, | ||
| 1507 | stamp.tm_hour, stamp.tm_min ); | ||
| 1508 | |||
| 1509 | if ( ( days_left > 0 ) && ( days_left <= server_certificate_min_days_valid ) ) { | ||
| 1510 | xasprintf( &msg, "Certificate expires in %d day(s) (%s).\n", days_left, timestamp ); | ||
| 1511 | ssl_terminate( STATE_WARNING, msg ); | ||
| 1512 | } | ||
| 1513 | if ( days_left < 0 ) { | ||
| 1514 | xasprintf( &msg, "Certificate expired on %s.\n", timestamp ); | ||
| 1515 | ssl_terminate( STATE_CRITICAL, msg ); | ||
| 1516 | } | ||
| 1517 | |||
| 1518 | if (days_left == 0) { | ||
| 1519 | xasprintf( &msg, "Certificate expires today (%s).\n", timestamp ); | ||
| 1520 | ssl_terminate( STATE_WARNING, msg ); | ||
| 1521 | } | ||
| 1522 | |||
| 1523 | xasprintf( &msg, "Certificate will expire on %s.\n", timestamp ); | ||
| 1524 | ssl_terminate( STATE_OK, msg ); | ||
| 1525 | } | ||
| 1526 | #endif | ||
| 1527 | |||
| 1528 | /* written by lauri alanko */ | ||
| 1529 | static char * | ||
| 1530 | base64 (char *bin, int len) | ||
| 1531 | { | ||
| 1532 | |||
| 1533 | char *buf = (char *) malloc ((len + 2) / 3 * 4 + 1); | ||
| 1534 | int i = 0, j = 0; | ||
| 1535 | |||
| 1536 | char BASE64_END = '='; | ||
| 1537 | char base64_table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||
| 1538 | |||
| 1539 | while (j < len - 2) { | ||
| 1540 | buf[i++] = base64_table[bin[j] >> 2]; | ||
| 1541 | buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)]; | ||
| 1542 | buf[i++] = base64_table[((bin[j + 1] & 15) << 2) | (bin[j + 2] >> 6)]; | ||
| 1543 | buf[i++] = base64_table[bin[j + 2] & 63]; | ||
| 1544 | j += 3; | ||
| 1545 | } | ||
| 1546 | |||
| 1547 | switch (len - j) { | ||
| 1548 | case 1: | ||
| 1549 | buf[i++] = base64_table[bin[j] >> 2]; | ||
| 1550 | buf[i++] = base64_table[(bin[j] & 3) << 4]; | ||
| 1551 | buf[i++] = BASE64_END; | ||
| 1552 | buf[i++] = BASE64_END; | ||
| 1553 | break; | ||
| 1554 | case 2: | ||
| 1555 | buf[i++] = base64_table[bin[j] >> 2]; | ||
| 1556 | buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)]; | ||
| 1557 | buf[i++] = base64_table[(bin[j + 1] & 15) << 2]; | ||
| 1558 | buf[i++] = BASE64_END; | ||
| 1559 | break; | ||
| 1560 | case 0: | ||
| 1561 | break; | ||
| 1562 | } | ||
| 1563 | |||
| 1564 | buf[i] = '\0'; | ||
| 1565 | return buf; | ||
| 1566 | } | ||
| 1567 | |||
diff --git a/contrib/check_linux_raid.pl b/contrib/check_linux_raid.pl index c24b0cd2..6650a42b 100644 --- a/contrib/check_linux_raid.pl +++ b/contrib/check_linux_raid.pl | |||
| @@ -28,8 +28,8 @@ use utils qw(%ERRORS); | |||
| 28 | 28 | ||
| 29 | # die with an error if we're not on Linux | 29 | # die with an error if we're not on Linux |
| 30 | if ($^O ne 'linux') { | 30 | if ($^O ne 'linux') { |
| 31 | print "This plugin only applicable on Linux.\n"; | 31 | print "This plugin only applicable on Linux.\n"; |
| 32 | exit $ERRORS{'UNKNOWN'}; | 32 | exit $ERRORS{'UNKNOWN'}; |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | sub max_state($$){ | 35 | sub max_state($$){ |
| @@ -50,6 +50,7 @@ my $code = "UNKNOWN"; | |||
| 50 | my $msg = ""; | 50 | my $msg = ""; |
| 51 | my %status; | 51 | my %status; |
| 52 | my %recovery; | 52 | my %recovery; |
| 53 | my %resyncing; | ||
| 53 | my %finish; | 54 | my %finish; |
| 54 | my %active; | 55 | my %active; |
| 55 | my %devices; | 56 | my %devices; |
| @@ -65,6 +66,10 @@ while(defined $nextdev){ | |||
| 65 | $recovery{$device} = $1; | 66 | $recovery{$device} = $1; |
| 66 | ($finish{$device}) = /finish=(.*?min)/; | 67 | ($finish{$device}) = /finish=(.*?min)/; |
| 67 | $device=undef; | 68 | $device=undef; |
| 69 | } elsif (/resync =\s+(.*?)\s/) { | ||
| 70 | $resyncing{$device} = $1; | ||
| 71 | ($finish{$device}) = /finish=(.*?min)/; | ||
| 72 | $device=undef; | ||
| 68 | } elsif (/^\s*$/) { | 73 | } elsif (/^\s*$/) { |
| 69 | $device=undef; | 74 | $device=undef; |
| 70 | } | 75 | } |
| @@ -95,8 +100,14 @@ foreach my $k (sort keys %devices){ | |||
| 95 | $code = max_state($code, "CRITICAL"); | 100 | $code = max_state($code, "CRITICAL"); |
| 96 | } | 101 | } |
| 97 | } elsif ($status{$k} =~ /U+/) { | 102 | } elsif ($status{$k} =~ /U+/) { |
| 98 | $msg .= sprintf " %s status=%s.", $devices{$k}, $status{$k}; | 103 | if (defined $resyncing{$k}) { |
| 99 | $code = max_state($code, "OK"); | 104 | $msg .= sprintf " %s status=%s, resync=%s, finish=%s.", |
| 105 | $devices{$k}, $status{$k}, $resyncing{$k}, $finish{$k}; | ||
| 106 | $code = max_state($code, "WARNING"); | ||
| 107 | } else { | ||
| 108 | $msg .= sprintf " %s status=%s.", $devices{$k}, $status{$k}; | ||
| 109 | $code = max_state($code, "OK"); | ||
| 110 | } | ||
| 100 | } else { | 111 | } else { |
| 101 | if ($active{$k}) { | 112 | if ($active{$k}) { |
| 102 | $msg .= sprintf " %s active with no status information.", | 113 | $msg .= sprintf " %s active with no status information.", |
| @@ -112,4 +123,3 @@ foreach my $k (sort keys %devices){ | |||
| 112 | 123 | ||
| 113 | print $code, $msg, "\n"; | 124 | print $code, $msg, "\n"; |
| 114 | exit ($ERRORS{$code}); | 125 | exit ($ERRORS{$code}); |
| 115 | |||
diff --git a/contrib/check_nmap.py b/contrib/check_nmap.py index 07f6d7fa..481a62bf 100644 --- a/contrib/check_nmap.py +++ b/contrib/check_nmap.py | |||
| @@ -43,7 +43,7 @@ _version_ = '1.21' | |||
| 43 | # 0.20 2000-07-10 jaclu Initial release | 43 | # 0.20 2000-07-10 jaclu Initial release |
| 44 | 44 | ||
| 45 | 45 | ||
| 46 | import sys, os, string, whrandom | 46 | import sys, os, string, random |
| 47 | 47 | ||
| 48 | import tempfile | 48 | import tempfile |
| 49 | from getopt import getopt | 49 | from getopt import getopt |
| @@ -207,8 +207,7 @@ class CheckNmap: | |||
| 207 | # _if_ two processes in deed get the same tmp-file | 207 | # _if_ two processes in deed get the same tmp-file |
| 208 | # the only result is a normal error message to nagios | 208 | # the only result is a normal error message to nagios |
| 209 | # | 209 | # |
| 210 | r=whrandom.whrandom() | 210 | self.tmp_file=tempfile.mktemp('.%s') % random.randint(0,100000) |
| 211 | self.tmp_file=tempfile.mktemp('.%s')%r.randint(0,100000) | ||
| 212 | if self.debug: | 211 | if self.debug: |
| 213 | print 'Tmpfile is: %s'%self.tmp_file | 212 | print 'Tmpfile is: %s'%self.tmp_file |
| 214 | # | 213 | # |
| @@ -388,7 +387,7 @@ Version: %s""" % _version_ | |||
| 388 | 387 | ||
| 389 | def doc_syntax(): | 388 | def doc_syntax(): |
| 390 | print """ | 389 | print """ |
| 391 | Usage: check_ports [-v|--debug] [-H|--host host] [-V|--version] [-h|--help] | 390 | Usage: check_nmap.py [-v|--debug] [-H|--host host] [-V|--version] [-h|--help] |
| 392 | [-o|--optional port1,port2,port3 ...] [-r|--range range] | 391 | [-o|--optional port1,port2,port3 ...] [-r|--range range] |
| 393 | [-p|--port port1,port2,port3 ...] [-t|--timeout timeout]""" | 392 | [-p|--port port1,port2,port3 ...] [-t|--timeout timeout]""" |
| 394 | 393 | ||
