Back to index

nagios-plugins  1.4.16
sslutils.c
Go to the documentation of this file.
00001 /*****************************************************************************
00002 * 
00003 * Nagios plugins SSL utilities
00004 * 
00005 * License: GPL
00006 * Copyright (c) 2005-2010 Nagios Plugins Development Team
00007 * 
00008 * Description:
00009 * 
00010 * This file contains common functions for plugins that require SSL.
00011 * 
00012 *
00013 * This program is free software: you can redistribute it and/or modify
00014 * it under the terms of the GNU General Public License as published by
00015 * the Free Software Foundation, either version 3 of the License, or
00016 * (at your option) any later version.
00017 * 
00018 * This program is distributed in the hope that it will be useful,
00019 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021 * GNU General Public License for more details.
00022 * 
00023 * You should have received a copy of the GNU General Public License
00024 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00025 * 
00026 * 
00027 *****************************************************************************/
00028 
00029 #define MAX_CN_LENGTH 256
00030 #define LOCAL_TIMEOUT_ALARM_HANDLER
00031 #include "common.h"
00032 #include "netutils.h"
00033 
00034 #ifdef HAVE_SSL
00035 static SSL_CTX *c=NULL;
00036 static SSL *s=NULL;
00037 static int initialized=0;
00038 
00039 int np_net_ssl_init(int sd) {
00040        return np_net_ssl_init_with_hostname(sd, NULL);
00041 }
00042 
00043 int np_net_ssl_init_with_hostname(int sd, char *host_name) {
00044        return np_net_ssl_init_with_hostname_and_version(sd, host_name, 0);
00045 }
00046 
00047 int np_net_ssl_init_with_hostname_and_version(int sd, char *host_name, int version) {
00048        const SSL_METHOD *method = NULL;
00049 
00050        switch (version) {
00051        case 0: /* Deafult to auto negotiation */
00052               method = SSLv23_client_method();
00053               break;
00054        case 1: /* TLSv1 protocol */
00055               method = TLSv1_client_method();
00056               break;
00057        case 2: /* SSLv2 protocol */
00058 #if defined(USE_GNUTLS) || defined(OPENSSL_NO_SSL2)
00059               printf(("%s\n", _("CRITICAL - SSL protocol version 2 is not supported by your SSL library.")));
00060               return STATE_CRITICAL;
00061 #else
00062               method = SSLv2_client_method();
00063 #endif
00064               break;
00065        case 3: /* SSLv3 protocol */
00066               method = SSLv3_client_method();
00067               break;
00068        default: /* Unsupported */
00069               printf("%s\n", _("CRITICAL - Unsupported SSL protocol version."));
00070               return STATE_CRITICAL;
00071        }
00072        if (!initialized) {
00073               /* Initialize SSL context */
00074               SSLeay_add_ssl_algorithms();
00075               SSL_load_error_strings();
00076               OpenSSL_add_all_algorithms();
00077               initialized = 1;
00078        }
00079        if ((c = SSL_CTX_new(method)) == NULL) {
00080               printf("%s\n", _("CRITICAL - Cannot create SSL context."));
00081               return STATE_CRITICAL;
00082        }
00083 #ifdef SSL_OP_NO_TICKET
00084        SSL_CTX_set_options(c, SSL_OP_NO_TICKET);
00085 #endif
00086        if ((s = SSL_new(c)) != NULL) {
00087 #ifdef SSL_set_tlsext_host_name
00088               if (host_name != NULL)
00089                      SSL_set_tlsext_host_name(s, host_name);
00090 #endif
00091               SSL_set_fd(s, sd);
00092               if (SSL_connect(s) == 1) {
00093                      return OK;
00094               } else {
00095                      printf("%s\n", _("CRITICAL - Cannot make SSL connection."));
00096 #  ifdef USE_OPENSSL /* XXX look into ERR_error_string */
00097                      ERR_print_errors_fp(stdout);
00098 #  endif /* USE_OPENSSL */
00099               }
00100        } else {
00101                      printf("%s\n", _("CRITICAL - Cannot initiate SSL handshake."));
00102        }
00103        return STATE_CRITICAL;
00104 }
00105 
00106 void np_net_ssl_cleanup() {
00107        if (s) {
00108 #ifdef SSL_set_tlsext_host_name
00109               SSL_set_tlsext_host_name(s, NULL);
00110 #endif
00111               SSL_shutdown(s);
00112               SSL_free(s);
00113               if (c) {
00114                      SSL_CTX_free(c);
00115                      c=NULL;
00116               }
00117               s=NULL;
00118        }
00119 }
00120 
00121 int np_net_ssl_write(const void *buf, int num) {
00122        return SSL_write(s, buf, num);
00123 }
00124 
00125 int np_net_ssl_read(void *buf, int num) {
00126        return SSL_read(s, buf, num);
00127 }
00128 
00129 int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit){
00130 #  ifdef USE_OPENSSL
00131        X509 *certificate=NULL;
00132        X509_NAME *subj=NULL;
00133        char cn[MAX_CN_LENGTH]= "";
00134        int cnlen =-1;
00135        int status=STATE_UNKNOWN;
00136 
00137        ASN1_STRING *tm;
00138        int offset;
00139        struct tm stamp;
00140        float time_left;
00141        int days_left;
00142        char timestamp[17] = "";
00143 
00144        certificate=SSL_get_peer_certificate(s);
00145        if (!certificate) {
00146               printf("%s\n",_("CRITICAL - Cannot retrieve server certificate."));
00147               return STATE_CRITICAL;
00148        }
00149 
00150        /* Extract CN from certificate subject */
00151        subj=X509_get_subject_name(certificate);
00152 
00153        if (!subj) {
00154               printf("%s\n",_("CRITICAL - Cannot retrieve certificate subject."));
00155               return STATE_CRITICAL;
00156        }
00157        cnlen = X509_NAME_get_text_by_NID(subj, NID_commonName, cn, sizeof(cn));
00158        if (cnlen == -1)
00159               strcpy(cn, _("Unknown CN"));
00160 
00161        /* Retrieve timestamp of certificate */
00162        tm = X509_get_notAfter(certificate);
00163 
00164        /* Generate tm structure to process timestamp */
00165        if (tm->type == V_ASN1_UTCTIME) {
00166               if (tm->length < 10) {
00167                      printf("%s\n", _("CRITICAL - Wrong time format in certificate."));
00168                      return STATE_CRITICAL;
00169               } else {
00170                      stamp.tm_year = (tm->data[0] - '0') * 10 + (tm->data[1] - '0');
00171                      if (stamp.tm_year < 50)
00172                             stamp.tm_year += 100;
00173                      offset = 0;
00174               }
00175        } else {
00176               if (tm->length < 12) {
00177                      printf("%s\n", _("CRITICAL - Wrong time format in certificate."));
00178                      return STATE_CRITICAL;
00179               } else {
00180                      stamp.tm_year =
00181                             (tm->data[0] - '0') * 1000 + (tm->data[1] - '0') * 100 +
00182                             (tm->data[2] - '0') * 10 + (tm->data[3] - '0');
00183                      stamp.tm_year -= 1900;
00184                      offset = 2;
00185               }
00186        }
00187        stamp.tm_mon =
00188               (tm->data[2 + offset] - '0') * 10 + (tm->data[3 + offset] - '0') - 1;
00189        stamp.tm_mday =
00190               (tm->data[4 + offset] - '0') * 10 + (tm->data[5 + offset] - '0');
00191        stamp.tm_hour =
00192               (tm->data[6 + offset] - '0') * 10 + (tm->data[7 + offset] - '0');
00193        stamp.tm_min =
00194               (tm->data[8 + offset] - '0') * 10 + (tm->data[9 + offset] - '0');
00195        stamp.tm_sec = 0;
00196        stamp.tm_isdst = -1;
00197 
00198        time_left = difftime(timegm(&stamp), time(NULL));
00199        days_left = time_left / 86400;
00200        snprintf
00201               (timestamp, 17, "%02d/%02d/%04d %02d:%02d",
00202                stamp.tm_mon + 1,
00203                stamp.tm_mday, stamp.tm_year + 1900, stamp.tm_hour, stamp.tm_min);
00204 
00205        if (days_left > 0 && days_left <= days_till_exp_warn) {
00206               printf (_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", cn, days_left, timestamp);
00207               if (days_left > days_till_exp_crit)
00208                      return STATE_WARNING;
00209               else
00210                      return STATE_CRITICAL;
00211        } else if (time_left < 0) {
00212               printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), cn, timestamp);
00213               status=STATE_CRITICAL;
00214        } else if (days_left == 0) {
00215               printf (_("%s - Certificate '%s' expires today (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", cn, timestamp);
00216               if (days_left > days_till_exp_crit)
00217                      return STATE_WARNING;
00218               else
00219                      return STATE_CRITICAL;
00220        } else {
00221               printf(_("OK - Certificate '%s' will expire on %s.\n"), cn, timestamp);
00222               status=STATE_OK;
00223        }
00224        X509_free(certificate);
00225        return status;
00226 #  else /* ifndef USE_OPENSSL */
00227        printf("%s\n", _("WARNING - Plugin does not support checking certificates."));
00228        return STATE_WARNING;
00229 #  endif /* USE_OPENSSL */
00230 }
00231 
00232 #endif /* HAVE_SSL */