2d2e28914875848d8f1ebd18f697dbd69d7d86f5
1 /******************************************************************************
2 *
3 * CHECK_SMTP.C
4 *
5 * Program: SMTP plugin for Nagios
6 * License: GPL
7 * Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
8 *
9 * $Id$
10 *
11 * Description:
12 *
13 * This plugin will attempt to open an SMTP connection with the host.
14 * Successul connects return STATE_OK, refusals and timeouts return
15 * STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful
16 * connects, but incorrect reponse messages from the host result in
17 * STATE_WARNING return values.
18 *
19 * License Information:
20 *
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
34 *
35 *****************************************************************************/
37 #include "config.h"
38 #include "common.h"
39 #include "netutils.h"
40 #include "utils.h"
42 #define PROGNAME "check_smtp"
44 #define SMTP_PORT 25
45 #define SMTP_EXPECT "220"
46 #define SMTP_HELO "HELO "
48 /* sendmail will syslog a "NOQUEUE" error if session does not attempt
49 * to do something useful. This can be prevented by giving a command
50 * even if syntax is illegal (MAIL requires a FROM:<...> argument)
51 * You can disable sending DUMMYCMD by undefining SMTP_USE_DUMMYCMD.
52 */
53 #define SMTP_DUMMYCMD "MAIL\r\n"
54 #define SMTP_USE_DUMMYCMD 1
55 #define SMTP_QUIT "QUIT\r\n"
57 int process_arguments (int, char **);
58 int call_getopt (int, char **);
59 int validate_arguments (void);
60 int check_disk (int usp, int free_disk);
61 void print_help (void);
62 void print_usage (void);
64 int server_port = SMTP_PORT;
65 char *server_address = NULL;
66 char *server_expect = NULL;
67 int warning_time = 0;
68 int check_warning_time = FALSE;
69 int critical_time = 0;
70 int check_critical_time = FALSE;
71 int verbose = FALSE;
73 int
74 main (int argc, char **argv)
75 {
76 int sd;
77 int result;
78 char buffer[MAX_INPUT_BUFFER] = "";
79 char helocmd[255] = SMTP_HELO ;
80 char myhostname[248];
83 if (process_arguments (argc, argv) != OK)
84 usage ("Invalid command arguments supplied\n");
86 /* initalize the HELO command with the localhostname */
87 gethostname(myhostname, sizeof(myhostname));
88 strcat(helocmd, myhostname);
89 strcat(helocmd, "\r\n");
91 /* initialize alarm signal handling */
92 signal (SIGALRM, socket_timeout_alarm_handler);
94 /* set socket timeout */
95 alarm (socket_timeout);
97 /* try to connect to the host at the given port number */
98 time (&start_time);
99 result = my_tcp_connect (server_address, server_port, &sd);
101 /* we connected, so close connection before exiting */
102 if (result == STATE_OK) {
104 /* watch for the SMTP connection string */
105 result = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0);
107 /* strip the buffer of carriage returns */
108 strip (buffer);
110 /* return a WARNING status if we couldn't read any data */
111 if (result == -1) {
112 printf ("recv() failed\n");
113 result = STATE_WARNING;
114 }
116 else {
118 /* make sure we find the response we are looking for */
119 if (!strstr (buffer, server_expect)) {
120 if (server_port == SMTP_PORT)
121 printf ("Invalid SMTP response received from host\n");
122 else
123 printf ("Invalid SMTP response received from host on port %d\n",
124 server_port);
125 result = STATE_WARNING;
126 }
128 else {
130 time (&end_time);
132 result = STATE_OK;
134 if (check_critical_time == TRUE
135 && (end_time - start_time) > critical_time) result =
136 STATE_CRITICAL;
137 else if (check_warning_time == TRUE
138 && (end_time - start_time) > warning_time) result =
139 STATE_WARNING;
141 if (verbose == TRUE)
142 printf ("SMTP %s - %d sec. response time, %s\n",
143 state_text (result), (int) (end_time - start_time), buffer);
144 else
145 printf ("SMTP %s - %d second response time\n", state_text (result),
146 (int) (end_time - start_time));
147 }
148 }
150 /* close the connection */
151 /* first send the HELO command */
152 send(sd,helocmd,strlen(helocmd),0);
153 /* allow for response to helo command to reach us */
154 recv(sd,buffer,MAX_INPUT_BUFFER-1,0);
156 #ifdef SMTP_USE_DUMMYCMD
157 send(sd,SMTP_DUMMYCMD,strlen(SMTP_DUMMYCMD),0);
158 /* allow for response to DUMMYCMD to reach us */
159 recv(sd,buffer,MAX_INPUT_BUFFER-1,0);
160 #endif /* SMTP_USE_DUMMYCMD */
162 /* finally close the connection */
163 send (sd, SMTP_QUIT, strlen (SMTP_QUIT), 0);
164 close (sd);
165 }
167 /* reset the alarm */
168 alarm (0);
170 return result;
171 }
178 /* process command-line arguments */
179 int
180 process_arguments (int argc, char **argv)
181 {
182 int c;
184 if (argc < 2)
185 return ERROR;
187 for (c = 1; c < argc; c++) {
188 if (strcmp ("-to", argv[c]) == 0)
189 strcpy (argv[c], "-t");
190 else if (strcmp ("-wt", argv[c]) == 0)
191 strcpy (argv[c], "-w");
192 else if (strcmp ("-ct", argv[c]) == 0)
193 strcpy (argv[c], "-c");
194 }
198 c = 0;
199 while ((c += (call_getopt (argc - c, &argv[c]))) < argc) {
201 if (is_option (argv[c]))
202 continue;
204 if (server_address == NULL) {
205 if (is_host (argv[c])) {
206 server_address = argv[c];
207 }
208 else {
209 usage ("Invalid host name");
210 }
211 }
212 }
214 if (server_address == NULL)
215 server_address = strscpy (NULL, "127.0.0.1");
217 if (server_expect == NULL)
218 server_expect = strscpy (NULL, SMTP_EXPECT);
220 return validate_arguments ();
221 }
228 int
229 call_getopt (int argc, char **argv)
230 {
231 int c, i = 0;
233 #ifdef HAVE_GETOPT_H
234 int option_index = 0;
235 static struct option long_options[] = {
236 {"hostname", required_argument, 0, 'H'},
237 {"expect", required_argument, 0, 'e'},
238 {"critical", required_argument, 0, 'c'},
239 {"warning", required_argument, 0, 'w'},
240 {"port", required_argument, 0, 'P'},
241 {"verbose", no_argument, 0, 'v'},
242 {"version", no_argument, 0, 'V'},
243 {"help", no_argument, 0, 'h'},
244 {0, 0, 0, 0}
245 };
246 #endif
248 while (1) {
249 #ifdef HAVE_GETOPT_H
250 c =
251 getopt_long (argc, argv, "+hVvt:p:e:c:w:H:", long_options,
252 &option_index);
253 #else
254 c = getopt (argc, argv, "+?hVvt:p:e:c:w:H:");
255 #endif
257 i++;
259 if (c == -1 || c == EOF || c == 1)
260 break;
262 switch (c) {
263 case 't':
264 case 'p':
265 case 'e':
266 case 'c':
267 case 'w':
268 case 'H':
269 i++;
270 }
272 switch (c) {
273 case 'H': /* hostname */
274 if (is_host (optarg)) {
275 server_address = optarg;
276 }
277 else {
278 usage ("Invalid host name\n");
279 }
280 break;
281 case 'p': /* port */
282 if (is_intpos (optarg)) {
283 server_port = atoi (optarg);
284 }
285 else {
286 usage ("Server port must be a positive integer\n");
287 }
288 break;
289 case 'e': /* username */
290 server_expect = optarg;
291 break;
292 case 'c': /* critical time threshold */
293 if (is_intnonneg (optarg)) {
294 critical_time = atoi (optarg);
295 check_critical_time = TRUE;
296 }
297 else {
298 usage ("Critical time must be a nonnegative integer\n");
299 }
300 break;
301 case 'w': /* warning time threshold */
302 if (is_intnonneg (optarg)) {
303 warning_time = atoi (optarg);
304 check_warning_time = TRUE;
305 }
306 else {
307 usage ("Warning time must be a nonnegative integer\n");
308 }
309 break;
310 case 'v': /* verbose */
311 verbose = TRUE;
312 break;
313 case 't': /* timeout */
314 if (is_intnonneg (optarg)) {
315 socket_timeout = atoi (optarg);
316 }
317 else {
318 usage ("Time interval must be a nonnegative integer\n");
319 }
320 break;
321 case 'V': /* version */
322 print_revision (PROGNAME, "$Revision$");
323 exit (STATE_OK);
324 case 'h': /* help */
325 print_help ();
326 exit (STATE_OK);
327 case '?': /* help */
328 usage ("Invalid argument\n");
329 }
330 }
331 return i;
332 }
338 int
339 validate_arguments (void)
340 {
341 return OK;
342 }
348 void
349 print_help (void)
350 {
351 print_revision (PROGNAME, "$Revision$");
352 printf
353 ("Copyright (c) 2000 Ethan Galstad/Karl DeBisschop\n\n"
354 "This plugin test the SMTP service on the specified host.\n\n");
355 print_usage ();
356 printf
357 ("\nOptions:\n"
358 " -H, --hostname=STRING or IPADDRESS\n"
359 " Check server on the indicated host\n"
360 " -p, --port=INTEGER\n"
361 " Make connection on the indicated port (default: %d)\n"
362 " -e, --expect=STRING\n"
363 " String to expect in first line of server response (default: %s)\n"
364 " -w, --warning=INTEGER\n"
365 " Seconds necessary to result in a warning status\n"
366 " -c, --critical=INTEGER\n"
367 " Seconds necessary to result in a critical status\n"
368 " -t, --timeout=INTEGER\n"
369 " Seconds before connection attempt times out (default: %d)\n"
370 " -v, --verbose\n"
371 " Print extra information (command-line use only)\n"
372 " -h, --help\n"
373 " Print detailed help screen\n"
374 " -V, --version\n"
375 " Print version information\n\n",
376 SMTP_PORT, SMTP_EXPECT, DEFAULT_SOCKET_TIMEOUT);
377 support ();
378 }
384 void
385 print_usage (void)
386 {
387 printf
388 ("Usage: %s -H host [-e expect] [-p port] [-w warn] [-c crit] [-t timeout] [-v]\n"
389 " %s --help\n"
390 " %s --version\n", PROGNAME, PROGNAME, PROGNAME);
391 }