Back to index

nagios-plugins  1.4.16
check_smtp.c
Go to the documentation of this file.
00001 /*****************************************************************************
00002 * 
00003 * Nagios check_smtp plugin
00004 * 
00005 * License: GPL
00006 * Copyright (c) 2000-2007 Nagios Plugins Development Team
00007 * 
00008 * Description:
00009 * 
00010 * This file contains the check_smtp plugin
00011 * 
00012 * This plugin will attempt to open an SMTP connection with the host.
00013 * 
00014 * 
00015 * This program is free software: you can redistribute it and/or modify
00016 * it under the terms of the GNU General Public License as published by
00017 * the Free Software Foundation, either version 3 of the License, or
00018 * (at your option) any later version.
00019 * 
00020 * This program is distributed in the hope that it will be useful,
00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023 * GNU General Public License for more details.
00024 * 
00025 * You should have received a copy of the GNU General Public License
00026 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00027 * 
00028 * 
00029 *****************************************************************************/
00030 
00031 const char *progname = "check_smtp";
00032 const char *copyright = "2000-2007";
00033 const char *email = "nagiosplug-devel@lists.sourceforge.net";
00034 
00035 #include "common.h"
00036 #include "netutils.h"
00037 #include "utils.h"
00038 #include "base64.h"
00039 
00040 #include <ctype.h>
00041 
00042 #ifdef HAVE_SSL
00043 int check_cert = FALSE;
00044 int days_till_exp_warn, days_till_exp_crit;
00045 #  define my_recv(buf, len) ((use_ssl && ssl_established) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
00046 #  define my_send(buf, len) ((use_ssl && ssl_established) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
00047 #else /* ifndef HAVE_SSL */
00048 #  define my_recv(buf, len) read(sd, buf, len)
00049 #  define my_send(buf, len) send(sd, buf, len, 0)
00050 #endif
00051 
00052 enum {
00053        SMTP_PORT     = 25
00054 };
00055 #define SMTP_EXPECT "220"
00056 #define SMTP_HELO "HELO "
00057 #define SMTP_EHLO "EHLO "
00058 #define SMTP_QUIT "QUIT\r\n"
00059 #define SMTP_STARTTLS "STARTTLS\r\n"
00060 #define SMTP_AUTH_LOGIN "AUTH LOGIN\r\n"
00061 
00062 #ifndef HOST_MAX_BYTES
00063 #define HOST_MAX_BYTES 255
00064 #endif
00065 
00066 #define EHLO_SUPPORTS_STARTTLS 1
00067 
00068 int process_arguments (int, char **);
00069 int validate_arguments (void);
00070 void print_help (void);
00071 void print_usage (void);
00072 void smtp_quit(void);
00073 int recvline(char *, size_t);
00074 int recvlines(char *, size_t);
00075 int my_close(void);
00076 
00077 #include "regex.h"
00078 char regex_expect[MAX_INPUT_BUFFER] = "";
00079 regex_t preg;
00080 regmatch_t pmatch[10];
00081 char timestamp[20] = "";
00082 char errbuf[MAX_INPUT_BUFFER];
00083 int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
00084 int eflags = 0;
00085 int errcode, excode;
00086 
00087 int server_port = SMTP_PORT;
00088 char *server_address = NULL;
00089 char *server_expect = NULL;
00090 int smtp_use_dummycmd = 0;
00091 char *mail_command = NULL;
00092 char *from_arg = NULL;
00093 int ncommands=0;
00094 int command_size=0;
00095 int nresponses=0;
00096 int response_size=0;
00097 char **commands = NULL;
00098 char **responses = NULL;
00099 char *authtype = NULL;
00100 char *authuser = NULL;
00101 char *authpass = NULL;
00102 int warning_time = 0;
00103 int check_warning_time = FALSE;
00104 int critical_time = 0;
00105 int check_critical_time = FALSE;
00106 int verbose = 0;
00107 int use_ssl = FALSE;
00108 short use_ehlo = FALSE;
00109 short ssl_established = 0;
00110 char *localhostname = NULL;
00111 int sd;
00112 char buffer[MAX_INPUT_BUFFER];
00113 enum {
00114   TCP_PROTOCOL = 1,
00115   UDP_PROTOCOL = 2,
00116 };
00117 int ignore_send_quit_failure = FALSE;
00118 
00119 
00120 int
00121 main (int argc, char **argv)
00122 {
00123        short supports_tls=FALSE;
00124        int n = 0;
00125        double elapsed_time;
00126        long microsec;
00127        int result = STATE_UNKNOWN;
00128        char *cmd_str = NULL;
00129        char *helocmd = NULL;
00130        char *error_msg = "";
00131        struct timeval tv;
00132 
00133        /* Catch pipe errors in read/write - sometimes occurs when writing QUIT */
00134        (void) signal (SIGPIPE, SIG_IGN);
00135 
00136        setlocale (LC_ALL, "");
00137        bindtextdomain (PACKAGE, LOCALEDIR);
00138        textdomain (PACKAGE);
00139 
00140        /* Parse extra opts if any */
00141        argv=np_extra_opts (&argc, argv, progname);
00142 
00143        if (process_arguments (argc, argv) == ERROR)
00144               usage4 (_("Could not parse arguments"));
00145 
00146        /* If localhostname not set on command line, use gethostname to set */
00147        if(! localhostname){
00148               localhostname = malloc (HOST_MAX_BYTES);
00149               if(!localhostname){
00150                      printf(_("malloc() failed!\n"));
00151                      return STATE_CRITICAL;
00152               }
00153               if(gethostname(localhostname, HOST_MAX_BYTES)){
00154                      printf(_("gethostname() failed!\n"));
00155                      return STATE_CRITICAL;
00156               }
00157        }
00158        if(use_ehlo)
00159               asprintf (&helocmd, "%s%s%s", SMTP_EHLO, localhostname, "\r\n");
00160        else
00161               asprintf (&helocmd, "%s%s%s", SMTP_HELO, localhostname, "\r\n");
00162 
00163        if (verbose)
00164               printf("HELOCMD: %s", helocmd);
00165 
00166        /* initialize the MAIL command with optional FROM command  */
00167        asprintf (&cmd_str, "%sFROM: %s%s", mail_command, from_arg, "\r\n");
00168 
00169        if (verbose && smtp_use_dummycmd)
00170               printf ("FROM CMD: %s", cmd_str);
00171 
00172        /* initialize alarm signal handling */
00173        (void) signal (SIGALRM, socket_timeout_alarm_handler);
00174 
00175        /* set socket timeout */
00176        (void) alarm (socket_timeout);
00177 
00178        /* start timer */
00179        gettimeofday (&tv, NULL);
00180 
00181        /* try to connect to the host at the given port number */
00182        result = my_tcp_connect (server_address, server_port, &sd);
00183 
00184        if (result == STATE_OK) { /* we connected */
00185 
00186               /* watch for the SMTP connection string and */
00187               /* return a WARNING status if we couldn't read any data */
00188               if (recvlines(buffer, MAX_INPUT_BUFFER) <= 0) {
00189                      printf (_("recv() failed\n"));
00190                      return STATE_WARNING;
00191               }
00192               else {
00193                      if (verbose)
00194                             printf ("%s", buffer);
00195                      /* strip the buffer of carriage returns */
00196                      strip (buffer);
00197                      /* make sure we find the response we are looking for */
00198                      if (!strstr (buffer, server_expect)) {
00199                             if (server_port == SMTP_PORT)
00200                                    printf (_("Invalid SMTP response received from host: %s\n"), buffer);
00201                             else
00202                                    printf (_("Invalid SMTP response received from host on port %d: %s\n"),
00203                                                                server_port, buffer);
00204                             return STATE_WARNING;
00205                      }
00206               }
00207 
00208               /* send the HELO/EHLO command */
00209               send(sd, helocmd, strlen(helocmd), 0);
00210 
00211               /* allow for response to helo command to reach us */
00212               if (recvlines(buffer, MAX_INPUT_BUFFER) <= 0) {
00213                      printf (_("recv() failed\n"));
00214                      return STATE_WARNING;
00215               } else if(use_ehlo){
00216                      if(strstr(buffer, "250 STARTTLS") != NULL ||
00217                         strstr(buffer, "250-STARTTLS") != NULL){
00218                             supports_tls=TRUE;
00219                      }
00220               }
00221 
00222               if(use_ssl && ! supports_tls){
00223                      printf(_("WARNING - TLS not supported by server\n"));
00224                      smtp_quit();
00225                      return STATE_WARNING;
00226               }
00227 
00228 #ifdef HAVE_SSL
00229               if(use_ssl) {
00230                 /* send the STARTTLS command */
00231                 send(sd, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0);
00232 
00233                 recvlines(buffer, MAX_INPUT_BUFFER); /* wait for it */
00234                 if (!strstr (buffer, server_expect)) {
00235                   printf (_("Server does not support STARTTLS\n"));
00236                   smtp_quit();
00237                   return STATE_UNKNOWN;
00238                 }
00239                 result = np_net_ssl_init(sd);
00240                 if(result != STATE_OK) {
00241                   printf (_("CRITICAL - Cannot create SSL context.\n"));
00242                   np_net_ssl_cleanup();
00243                   close(sd);
00244                   return STATE_CRITICAL;
00245                 } else {
00246                      ssl_established = 1;
00247                 }
00248 
00249               /*
00250                * Resend the EHLO command.
00251                *
00252                * RFC 3207 (4.2) says: ``The client MUST discard any knowledge
00253                * obtained from the server, such as the list of SMTP service
00254                * extensions, which was not obtained from the TLS negotiation
00255                * itself.  The client SHOULD send an EHLO command as the first
00256                * command after a successful TLS negotiation.''  For this
00257                * reason, some MTAs will not allow an AUTH LOGIN command before
00258                * we resent EHLO via TLS.
00259                */
00260               if (my_send(helocmd, strlen(helocmd)) <= 0) {
00261                      printf("%s\n", _("SMTP UNKNOWN - Cannot send EHLO command via TLS."));
00262                      my_close();
00263                      return STATE_UNKNOWN;
00264               }
00265               if (verbose)
00266                      printf(_("sent %s"), helocmd);
00267               if ((n = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) {
00268                      printf("%s\n", _("SMTP UNKNOWN - Cannot read EHLO response via TLS."));
00269                      my_close();
00270                      return STATE_UNKNOWN;
00271               }
00272               if (verbose) {
00273                      printf("%s", buffer);
00274               }
00275 
00276 #  ifdef USE_OPENSSL
00277                 if ( check_cert ) {
00278                     result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit);
00279                   my_close();
00280                   return result;
00281                 }
00282 #  endif /* USE_OPENSSL */
00283               }
00284 #endif
00285 
00286               /* sendmail will syslog a "NOQUEUE" error if session does not attempt
00287                * to do something useful. This can be prevented by giving a command
00288                * even if syntax is illegal (MAIL requires a FROM:<...> argument)
00289                *
00290                * According to rfc821 you can include a null reversepath in the from command
00291                * - but a log message is generated on the smtp server.
00292                *
00293                * Use the -f option to provide a FROM address
00294                */
00295               if (smtp_use_dummycmd) {
00296                 my_send(cmd_str, strlen(cmd_str));
00297                 if (recvlines(buffer, MAX_INPUT_BUFFER) >= 1 && verbose)
00298                   printf("%s", buffer);
00299               }
00300 
00301               while (n < ncommands) {
00302                      asprintf (&cmd_str, "%s%s", commands[n], "\r\n");
00303                      my_send(cmd_str, strlen(cmd_str));
00304                      if (recvlines(buffer, MAX_INPUT_BUFFER) >= 1 && verbose)
00305                             printf("%s", buffer);
00306                      strip (buffer);
00307                      if (n < nresponses) {
00308                             cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
00309                             errcode = regcomp (&preg, responses[n], cflags);
00310                             if (errcode != 0) {
00311                                    regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
00312                                    printf (_("Could Not Compile Regular Expression"));
00313                                    return ERROR;
00314                             }
00315                             excode = regexec (&preg, buffer, 10, pmatch, eflags);
00316                             if (excode == 0) {
00317                                    result = STATE_OK;
00318                             }
00319                             else if (excode == REG_NOMATCH) {
00320                                    result = STATE_WARNING;
00321                                    printf (_("SMTP %s - Invalid response '%s' to command '%s'\n"), state_text (result), buffer, commands[n]);
00322                             }
00323                             else {
00324                                    regerror (excode, &preg, errbuf, MAX_INPUT_BUFFER);
00325                                    printf (_("Execute Error: %s\n"), errbuf);
00326                                    result = STATE_UNKNOWN;
00327                             }
00328                      }
00329                      n++;
00330               }
00331 
00332               if (authtype != NULL) {
00333                      if (strcmp (authtype, "LOGIN") == 0) {
00334                             char *abuf;
00335                             int ret;
00336                             do {
00337                                    if (authuser == NULL) {
00338                                           result = STATE_CRITICAL;
00339                                           asprintf(&error_msg, _("no authuser specified, "));
00340                                           break;
00341                                    }
00342                                    if (authpass == NULL) {
00343                                           result = STATE_CRITICAL;
00344                                           asprintf(&error_msg, _("no authpass specified, "));
00345                                           break;
00346                                    }
00347 
00348                                    /* send AUTH LOGIN */
00349                                    my_send(SMTP_AUTH_LOGIN, strlen(SMTP_AUTH_LOGIN));
00350                                    if (verbose)
00351                                           printf (_("sent %s\n"), "AUTH LOGIN");
00352 
00353                                    if ((ret = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) {
00354                                           asprintf(&error_msg, _("recv() failed after AUTH LOGIN, "));
00355                                           result = STATE_WARNING;
00356                                           break;
00357                                    }
00358                                    if (verbose)
00359                                           printf (_("received %s\n"), buffer);
00360 
00361                                    if (strncmp (buffer, "334", 3) != 0) {
00362                                           result = STATE_CRITICAL;
00363                                           asprintf(&error_msg, _("invalid response received after AUTH LOGIN, "));
00364                                           break;
00365                                    }
00366 
00367                                    /* encode authuser with base64 */
00368                                    base64_encode_alloc (authuser, strlen(authuser), &abuf);
00369                                    /* FIXME: abuf shouldn't have enough space to strcat a '\r\n' into it. */
00370                                    strcat (abuf, "\r\n");
00371                                    my_send(abuf, strlen(abuf));
00372                                    if (verbose)
00373                                           printf (_("sent %s\n"), abuf);
00374 
00375                                    if ((ret = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) {
00376                                           result = STATE_CRITICAL;
00377                                           asprintf(&error_msg, _("recv() failed after sending authuser, "));
00378                                           break;
00379                                    }
00380                                    if (verbose) {
00381                                           printf (_("received %s\n"), buffer);
00382                                    }
00383                                    if (strncmp (buffer, "334", 3) != 0) {
00384                                           result = STATE_CRITICAL;
00385                                           asprintf(&error_msg, _("invalid response received after authuser, "));
00386                                           break;
00387                                    }
00388                                    /* encode authpass with base64 */
00389                                    base64_encode_alloc (authpass, strlen(authpass), &abuf);
00390                                    /* FIXME: abuf shouldn't have enough space to strcat a '\r\n' into it. */
00391                                    strcat (abuf, "\r\n");
00392                                    my_send(abuf, strlen(abuf));
00393                                    if (verbose) {
00394                                           printf (_("sent %s\n"), abuf);
00395                                    }
00396                                    if ((ret = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) {
00397                                           result = STATE_CRITICAL;
00398                                           asprintf(&error_msg, _("recv() failed after sending authpass, "));
00399                                           break;
00400                                    }
00401                                    if (verbose) {
00402                                           printf (_("received %s\n"), buffer);
00403                                    }
00404                                    if (strncmp (buffer, "235", 3) != 0) {
00405                                           result = STATE_CRITICAL;
00406                                           asprintf(&error_msg, _("invalid response received after authpass, "));
00407                                           break;
00408                                    }
00409                                    break;
00410                             } while (0);
00411                      } else {
00412                             result = STATE_CRITICAL;
00413                             asprintf(&error_msg, _("only authtype LOGIN is supported, "));
00414                      }
00415               }
00416 
00417               /* tell the server we're done */
00418               smtp_quit();
00419 
00420               /* finally close the connection */
00421               close (sd);
00422        }
00423 
00424        /* reset the alarm */
00425        alarm (0);
00426 
00427        microsec = deltime (tv);
00428        elapsed_time = (double)microsec / 1.0e6;
00429 
00430        if (result == STATE_OK) {
00431               if (check_critical_time && elapsed_time > (double) critical_time)
00432                      result = STATE_CRITICAL;
00433               else if (check_warning_time && elapsed_time > (double) warning_time)
00434                      result = STATE_WARNING;
00435        }
00436 
00437        printf (_("SMTP %s - %s%.3f sec. response time%s%s|%s\n"),
00438                      state_text (result),
00439                      error_msg,
00440                      elapsed_time,
00441                      verbose?", ":"", verbose?buffer:"",
00442                      fperfdata ("time", elapsed_time, "s",
00443                             (int)check_warning_time, warning_time,
00444                             (int)check_critical_time, critical_time,
00445                             TRUE, 0, FALSE, 0));
00446 
00447        return result;
00448 }
00449 
00450 
00451 
00452 /* process command-line arguments */
00453 int
00454 process_arguments (int argc, char **argv)
00455 {
00456        int c;
00457        char* temp;
00458 
00459        int option = 0;
00460        static struct option longopts[] = {
00461               {"hostname", required_argument, 0, 'H'},
00462               {"expect", required_argument, 0, 'e'},
00463               {"critical", required_argument, 0, 'c'},
00464               {"warning", required_argument, 0, 'w'},
00465               {"timeout", required_argument, 0, 't'},
00466               {"port", required_argument, 0, 'p'},
00467               {"from", required_argument, 0, 'f'},
00468               {"fqdn", required_argument, 0, 'F'},
00469               {"authtype", required_argument, 0, 'A'},
00470               {"authuser", required_argument, 0, 'U'},
00471               {"authpass", required_argument, 0, 'P'},
00472               {"command", required_argument, 0, 'C'},
00473               {"response", required_argument, 0, 'R'},
00474               {"verbose", no_argument, 0, 'v'},
00475               {"version", no_argument, 0, 'V'},
00476               {"use-ipv4", no_argument, 0, '4'},
00477               {"use-ipv6", no_argument, 0, '6'},
00478               {"help", no_argument, 0, 'h'},
00479               {"starttls",no_argument,0,'S'},
00480               {"certificate",required_argument,0,'D'},
00481               {"ignore-quit-failure",no_argument,0,'q'},
00482               {0, 0, 0, 0}
00483        };
00484 
00485        if (argc < 2)
00486               return ERROR;
00487 
00488        for (c = 1; c < argc; c++) {
00489               if (strcmp ("-to", argv[c]) == 0)
00490                      strcpy (argv[c], "-t");
00491               else if (strcmp ("-wt", argv[c]) == 0)
00492                      strcpy (argv[c], "-w");
00493               else if (strcmp ("-ct", argv[c]) == 0)
00494                      strcpy (argv[c], "-c");
00495        }
00496 
00497        while (1) {
00498               c = getopt_long (argc, argv, "+hVv46t:p:f:e:c:w:H:C:R:SD:F:A:U:P:q",
00499                                longopts, &option);
00500 
00501               if (c == -1 || c == EOF)
00502                      break;
00503 
00504               switch (c) {
00505               case 'H':                                                             /* hostname */
00506                      if (is_host (optarg)) {
00507                             server_address = optarg;
00508                      }
00509                      else {
00510                             usage2 (_("Invalid hostname/address"), optarg);
00511                      }
00512                      break;
00513               case 'p':                                                             /* port */
00514                      if (is_intpos (optarg))
00515                             server_port = atoi (optarg);
00516                      else
00517                             usage4 (_("Port must be a positive integer"));
00518                      break;
00519               case 'F':
00520               /* localhostname */
00521                      localhostname = strdup(optarg);
00522                      break;
00523               case 'f':                                                             /* from argument */
00524                      from_arg = optarg;
00525                      smtp_use_dummycmd = 1;
00526                      break;
00527               case 'A':
00528                      authtype = optarg;
00529                      use_ehlo = TRUE;
00530                      break;
00531               case 'U':
00532                      authuser = optarg;
00533                      break;
00534               case 'P':
00535                      authpass = optarg;
00536                      break;
00537               case 'e':                                                             /* server expect string on 220  */
00538                      server_expect = optarg;
00539                      break;
00540               case 'C':                                                             /* commands  */
00541                      if (ncommands >= command_size) {
00542                             command_size+=8;
00543                             commands = realloc (commands, sizeof(char *) * command_size);
00544                             if (commands == NULL)
00545                                    die (STATE_UNKNOWN,
00546                                         _("Could not realloc() units [%d]\n"), ncommands);
00547                      }
00548                      commands[ncommands] = (char *) malloc (sizeof(char) * 255);
00549                      strncpy (commands[ncommands], optarg, 255);
00550                      ncommands++;
00551                      break;
00552               case 'R':                                                             /* server responses */
00553                      if (nresponses >= response_size) {
00554                             response_size += 8;
00555                             responses = realloc (responses, sizeof(char *) * response_size);
00556                             if (responses == NULL)
00557                                    die (STATE_UNKNOWN,
00558                                         _("Could not realloc() units [%d]\n"), nresponses);
00559                      }
00560                      responses[nresponses] = (char *) malloc (sizeof(char) * 255);
00561                      strncpy (responses[nresponses], optarg, 255);
00562                      nresponses++;
00563                      break;
00564               case 'c':                                                             /* critical time threshold */
00565                      if (is_intnonneg (optarg)) {
00566                             critical_time = atoi (optarg);
00567                             check_critical_time = TRUE;
00568                      }
00569                      else {
00570                             usage4 (_("Critical time must be a positive integer"));
00571                      }
00572                      break;
00573               case 'w':                                                             /* warning time threshold */
00574                      if (is_intnonneg (optarg)) {
00575                             warning_time = atoi (optarg);
00576                             check_warning_time = TRUE;
00577                      }
00578                      else {
00579                             usage4 (_("Warning time must be a positive integer"));
00580                      }
00581                      break;
00582               case 'v':                                                             /* verbose */
00583                      verbose++;
00584                      break;
00585               case 'q':
00586                      ignore_send_quit_failure++;             /* ignore problem sending QUIT */
00587                      break;
00588               case 't':                                                             /* timeout */
00589                      if (is_intnonneg (optarg)) {
00590                             socket_timeout = atoi (optarg);
00591                      }
00592                      else {
00593                             usage4 (_("Timeout interval must be a positive integer"));
00594                      }
00595                      break;
00596               case 'S':
00597               /* starttls */
00598                      use_ssl = TRUE;
00599                      use_ehlo = TRUE;
00600                      break;
00601               case 'D':
00602               /* Check SSL cert validity */
00603 #ifdef USE_OPENSSL
00604                         if ((temp=strchr(optarg,','))!=NULL) {
00605                             *temp='\0';
00606                             if (!is_intnonneg (temp))
00607                                usage2 ("Invalid certificate expiration period", optarg);
00608                             days_till_exp_warn = atoi(optarg);
00609                             *temp=',';
00610                             temp++;
00611                             if (!is_intnonneg (temp))
00612                                 usage2 (_("Invalid certificate expiration period"), temp);
00613                             days_till_exp_crit = atoi (temp);
00614                         }
00615                         else {
00616                             days_till_exp_crit=0;
00617                             if (!is_intnonneg (optarg))
00618                                 usage2 ("Invalid certificate expiration period", optarg);
00619                             days_till_exp_warn = atoi (optarg);
00620                         }
00621                      check_cert = TRUE;
00622 #else
00623                      usage (_("SSL support not available - install OpenSSL and recompile"));
00624 #endif
00625                      break;
00626               case '4':
00627                      address_family = AF_INET;
00628                      break;
00629               case '6':
00630 #ifdef USE_IPV6
00631                      address_family = AF_INET6;
00632 #else
00633                      usage4 (_("IPv6 support not available"));
00634 #endif
00635                      break;
00636               case 'V':                                                             /* version */
00637                      print_revision (progname, NP_VERSION);
00638                      exit (STATE_OK);
00639               case 'h':                                                             /* help */
00640                      print_help ();
00641                      exit (STATE_OK);
00642               case '?':                                                             /* help */
00643                      usage5 ();
00644               }
00645        }
00646 
00647        c = optind;
00648        if (server_address == NULL) {
00649               if (argv[c]) {
00650                      if (is_host (argv[c]))
00651                             server_address = argv[c];
00652                      else
00653                             usage2 (_("Invalid hostname/address"), argv[c]);
00654               }
00655               else {
00656                      asprintf (&server_address, "127.0.0.1");
00657               }
00658        }
00659 
00660        if (server_expect == NULL)
00661               server_expect = strdup (SMTP_EXPECT);
00662 
00663        if (mail_command == NULL)
00664               mail_command = strdup("MAIL ");
00665 
00666        if (from_arg==NULL)
00667               from_arg = strdup(" ");
00668 
00669        return validate_arguments ();
00670 }
00671 
00672 
00673 
00674 int
00675 validate_arguments (void)
00676 {
00677        return OK;
00678 }
00679 
00680 
00681 void
00682 smtp_quit(void)
00683 {
00684        int bytes;
00685        int n;
00686 
00687        n = my_send(SMTP_QUIT, strlen(SMTP_QUIT));
00688        if(n < 0) {
00689               if(ignore_send_quit_failure) {
00690                      if(verbose) {
00691                             printf(_("Connection closed by server before sending QUIT command\n"));
00692                      }
00693                      return;
00694               }
00695               die (STATE_UNKNOWN,
00696                      _("Connection closed by server before sending QUIT command\n"));
00697        }
00698 
00699        if (verbose)
00700               printf(_("sent %s\n"), "QUIT");
00701 
00702        /* read the response but don't care about problems */
00703        bytes = recvlines(buffer, MAX_INPUT_BUFFER);
00704        if (verbose) {
00705               if (bytes < 0)
00706                      printf(_("recv() failed after QUIT."));
00707               else if (bytes == 0)
00708                      printf(_("Connection reset by peer."));
00709               else {
00710                      buffer[bytes] = '\0';
00711                      printf(_("received %s\n"), buffer);
00712               }
00713        }
00714 }
00715 
00716 
00717 /*
00718  * Receive one line, copy it into buf and nul-terminate it.  Returns the
00719  * number of bytes written to buf (excluding the '\0') or 0 on EOF or <0 on
00720  * error.
00721  *
00722  * TODO: Reading one byte at a time is very inefficient.  Replace this by a
00723  * function which buffers the data, move that to netutils.c and change
00724  * check_smtp and other plugins to use that.  Also, remove (\r)\n.
00725  */
00726 int
00727 recvline(char *buf, size_t bufsize)
00728 {
00729        int result;
00730        unsigned i;
00731 
00732        for (i = result = 0; i < bufsize - 1; i++) {
00733               if ((result = my_recv(&buf[i], 1)) != 1)
00734                      break;
00735               if (buf[i] == '\n') {
00736                      buf[++i] = '\0';
00737                      return i;
00738               }
00739        }
00740        return (result == 1 || i == 0) ? -2 : result;    /* -2 if out of space */
00741 }
00742 
00743 
00744 /*
00745  * Receive one or more lines, copy them into buf and nul-terminate it.  Returns
00746  * the number of bytes written to buf (excluding the '\0') or 0 on EOF or <0 on
00747  * error.  Works for all protocols which format multiline replies as follows:
00748  *
00749  * ``The format for multiline replies requires that every line, except the last,
00750  * begin with the reply code, followed immediately by a hyphen, `-' (also known
00751  * as minus), followed by text.  The last line will begin with the reply code,
00752  * followed immediately by <SP>, optionally some text, and <CRLF>.  As noted
00753  * above, servers SHOULD send the <SP> if subsequent text is not sent, but
00754  * clients MUST be prepared for it to be omitted.'' (RFC 2821, 4.2.1)
00755  *
00756  * TODO: Move this to netutils.c.  Also, remove \r and possibly the final \n.
00757  */
00758 int
00759 recvlines(char *buf, size_t bufsize)
00760 {
00761        int result, i;
00762 
00763        for (i = 0; /* forever */; i += result)
00764               if (!((result = recvline(buf + i, bufsize - i)) > 3 &&
00765                   isdigit((int)buf[i]) &&
00766                   isdigit((int)buf[i + 1]) &&
00767                   isdigit((int)buf[i + 2]) &&
00768                   buf[i + 3] == '-'))
00769                      break;
00770 
00771        return (result <= 0) ? result : result + i;
00772 }
00773 
00774 
00775 int
00776 my_close (void)
00777 {
00778 #ifdef HAVE_SSL
00779   np_net_ssl_cleanup();
00780 #endif
00781   return close(sd);
00782 }
00783 
00784 
00785 void
00786 print_help (void)
00787 {
00788        char *myport;
00789        asprintf (&myport, "%d", SMTP_PORT);
00790 
00791        print_revision (progname, NP_VERSION);
00792 
00793        printf ("Copyright (c) 1999-2001 Ethan Galstad <nagios@nagios.org>\n");
00794        printf (COPYRIGHT, copyright, email);
00795 
00796        printf("%s\n", _("This plugin will attempt to open an SMTP connection with the host."));
00797 
00798   printf ("\n\n");
00799 
00800        print_usage ();
00801 
00802        printf (UT_HELP_VRSN);
00803        printf (UT_EXTRA_OPTS);
00804 
00805        printf (UT_HOST_PORT, 'p', myport);
00806 
00807        printf (UT_IPv46);
00808 
00809        printf (" %s\n", "-e, --expect=STRING");
00810   printf (_("    String to expect in first line of server response (default: '%s')\n"), SMTP_EXPECT);
00811   printf (" %s\n", "-C, --command=STRING");
00812   printf ("    %s\n", _("SMTP command (may be used repeatedly)"));
00813   printf (" %s\n", "-R, --command=STRING");
00814   printf ("    %s\n", _("Expected response to command (may be used repeatedly)"));
00815   printf (" %s\n", "-f, --from=STRING");
00816   printf ("    %s\n", _("FROM-address to include in MAIL command, required by Exchange 2000")),
00817   printf (" %s\n", "-F, --fqdn=STRING");
00818   printf ("    %s\n", _("FQDN used for HELO"));
00819 #ifdef HAVE_SSL
00820   printf (" %s\n", "-D, --certificate=INTEGER[,INTEGER]");
00821   printf ("    %s\n", _("Minimum number of days a certificate has to be valid."));
00822   printf (" %s\n", "-S, --starttls");
00823   printf ("    %s\n", _("Use STARTTLS for the connection."));
00824 #endif
00825 
00826        printf (" %s\n", "-A, --authtype=STRING");
00827   printf ("    %s\n", _("SMTP AUTH type to check (default none, only LOGIN supported)"));
00828   printf (" %s\n", "-U, --authuser=STRING");
00829   printf ("    %s\n", _("SMTP AUTH username"));
00830   printf (" %s\n", "-P, --authpass=STRING");
00831   printf ("    %s\n", _("SMTP AUTH password"));
00832   printf (" %s\n", "-q, --ignore-quit-failure");
00833   printf ("    %s\n", _("Ignore failure when sending QUIT command to server"));
00834    
00835        printf (UT_WARN_CRIT);
00836 
00837        printf (UT_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
00838 
00839        printf (UT_VERBOSE);
00840 
00841        printf("\n");
00842        printf ("%s\n", _("Successul connects return STATE_OK, refusals and timeouts return"));
00843   printf ("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN.  Successful"));
00844   printf ("%s\n", _("connects, but incorrect reponse messages from the host result in"));
00845   printf ("%s\n", _("STATE_WARNING return values."));
00846 
00847        printf (UT_SUPPORT);
00848 }
00849 
00850 
00851 
00852 void
00853 print_usage (void)
00854 {
00855   printf ("%s\n", _("Usage:"));
00856   printf ("%s -H host [-p port] [-4|-6] [-e expect] [-C command] [-f from addr]", progname);
00857   printf ("[-A authtype -U authuser -P authpass] [-w warn] [-c crit] [-t timeout] [-q]\n");
00858   printf ("[-F fqdn] [-S] [-D warn days cert expire[,crit days cert expire]] [-v] \n");
00859 }
00860