1 /* $Id: smtp.c,v 1.20 2006/05/09 03:26:42 jared Exp $ */
2 #include "config.h"
3
4 /* error banners 451 - out of memory */
5
6 /* ok banner 220 */
7
8 struct smtpdata {
9 time_t start; /* test start time */
10 time_t lastact; /* last activity */
11 int state;
12 };
13
14 #define SMTP_CONNECT 1 /* doing a connect() */
15 #define SMTP_WAITBAN 2 /* Waiting for the banner */
16 #define SMTP_SENT_QUIT 3 /* sent a QUIT */
17 #define SMTP_GOT_BYE 4 /* got a bye from the remote server */
18
19 /*
20
21 Here's the deal with smtp checks. We do this:
22
23 We connect, and do this:
24
25 server>220 puck.nether.net ESMTP
26 us<QUIT
27 server>221 puck.nether.net closing connection
28
29 If we get anything else, we return SYSM_BAD_RESP
30
31 If inactivity on socket is more than globtimeout, we return
32 SYSM_NORESP
33
34 */
35
start_test_smtp(struct monitorent * here,time_t now_t)36 void start_test_smtp(struct monitorent *here, time_t now_t)
37 {
38 struct smtpdata *localstruct = NULL;
39 struct my_hostent *hp = NULL;
40 struct sockaddr_in name;
41 int serrno = -1, errcode = 0;
42
43 /* Allocate our memory */
44 here->monitordata = MALLOC(sizeof(struct smtpdata), "smtp localstruct");
45
46 localstruct = here->monitordata;
47
48 localstruct->start = now_t;
49
50 localstruct->lastact = localstruct->start;
51
52 here->filedes = open_sock();
53
54 if (here->filedes == -1)
55 {
56 here->retval = here->checkent->lastcheck;
57 FREE(here->monitordata);
58 here->monitordata = NULL;
59 return;
60 }
61
62 hp = my_gethostbyname(here->checkent->hostname, AF_INET);
63
64 if (hp == NULL)
65 {
66 here->retval = SYSM_NODNS;
67 FREE(here->monitordata);
68 here->monitordata = NULL;
69 return;
70 }
71
72 /* zero out the space */
73 memset ( &name, 0, sizeof ( name ) );
74
75 /* copy data */
76 memcpy((char*)&name.sin_addr, (char*)hp->my_h_addr_v4, hp->h_length_v4);
77
78 /* set family type */
79 name.sin_family = AF_INET;
80
81 /* set the port we're connecting to */
82 name.sin_port = htons(SMTP_PORTNUM);
83
84 if (debug || here->checkent->trace)
85 {
86 print_err(here->checkent->trace, "start_test_smtp() doing connect() to %s:%d",
87 here->checkent->hostname, SMTP_PORTNUM);
88 }
89
90 errcode = connect(here->filedes, (struct sockaddr*)&name,
91 sizeof(struct sockaddr_in));
92 serrno = errno;
93 if (debug)
94 {
95 perror("connect() in start_smtp");
96 }
97
98 if ((errcode < 0) && (serrno != EINPROGRESS))
99 {
100 if (close(here->filedes) == -1)
101 {
102 perror("smtp.c: closing fd");
103 }
104 here->retval = errno_to_error(serrno);
105
106 /* Free memory we'd normally leak */
107 FREE(localstruct);
108 here->monitordata = NULL;
109
110 print_err(0, "smtp: retval = %d\n", here->retval);
111 return;
112 }
113
114 /* doing a connect() */
115 localstruct->state = SMTP_CONNECT;
116
117 /* poll it again later */
118 return;
119 }
120
service_test_smtp(struct monitorent * here,time_t now_t)121 void service_test_smtp(struct monitorent *here, time_t now_t)
122 {
123 /* do the actual real parts of the checks after
124 it's been set up */
125
126 struct smtpdata *localstruct = NULL;
127 char buffer[256];
128 int isopenretval = -1;
129 int bytes = 0;
130
131 /* Check for problems */
132 if (here == NULL)
133 {
134 return;
135 }
136
137 /* do some variable shuffling */
138
139 localstruct = here->monitordata;
140
141 if (localstruct == NULL)
142 {
143 print_err(0, "bug! localstruct == NULL in smtp.c:service_test_smtp");
144 return;
145 }
146
147 if (debug || here->checkent->trace)
148 {
149 print_err(here->checkent->trace, "in service_test_smtp and the state is %d",localstruct->state);
150 }
151
152 /* do different things based on the state */
153 switch (localstruct->state)
154 {
155 case SMTP_CONNECT:
156 {
157 isopenretval = is_open(here->filedes);
158 if ((isopenretval != -1) &&
159 (isopenretval != SYSM_INPROG))
160 {
161 localstruct->lastact = now_t;
162 if (debug || here->checkent->trace)
163 print_err(here->checkent->trace, "is_open() in service_test_smtp()");
164 if (isopenretval != SYSM_OK)
165 {
166 here->retval = isopenretval;
167 close(here->filedes);
168 FREE(localstruct);
169 here->monitordata = NULL;
170 if (debug || here->checkent->trace)
171 print_err(here->checkent->trace, "ending service_test_smtp() with retval = %s", errtostr(here->retval));
172 return;
173 }
174 localstruct->state = SMTP_WAITBAN;
175 if (debug || here->checkent->trace)
176 print_err(here->checkent->trace, "connected() to the smtp port of %s", here->checkent->hostname);
177 }
178 if ((now_t-localstruct->start) >= globtimeout)
179 {
180 here->retval = SYSM_TIMEDOUT;
181 close(here->filedes);
182 FREE(localstruct);
183 here->monitordata = NULL;
184 if (debug || here->checkent->trace)
185 {
186 print_err(here->checkent->trace, "ending service_test_smtp() with retval = %s",
187 errtostr(here->retval));
188 }
189 return;
190 }
191 break;
192 }
193 case SMTP_WAITBAN:
194 {
195 if (data_waiting_read(here->filedes, 0))
196 {
197 memset(buffer, 0, 256);
198 bytes =read(here->filedes, buffer, 254);
199 if (bytes != 0 && bytes != -1)
200 {
201 buffer[strlen(buffer)-1] = '\0';
202 } else if (bytes == -1) {
203 perror("smtp.c:service_test_smtp:read");
204 }
205
206 if (debug || here->checkent->trace)
207 print_err(0, "Got :%s:", buffer);
208 if (strncmp(buffer, "220", 3) == 0)
209 {
210 localstruct->state = SMTP_SENT_QUIT;
211 } else {
212 print_err(1, "smtp.c:got %s from %s", buffer, here->checkent->hostname);
213 here->retval = SYSM_BAD_RESP;
214 }
215 sendline(here->filedes, "QUIT");
216 }
217 break;
218 }
219 case SMTP_SENT_QUIT:
220 {
221 if (data_waiting_read(here->filedes, 0))
222 {
223 memset(buffer, 0, 256);
224 bytes = read(here->filedes, buffer, 254);
225 if (bytes != 0 && bytes != -1)
226 {
227 buffer[strlen(buffer)-1] = '\0';
228 } else if (bytes == -1) {
229 perror("smtp.c:service_test_smtp:read");
230 }
231 if (debug || here->checkent->trace)
232 print_err(here->checkent->trace, "smtp.c:sending_quit_received:%s:", buffer);
233 if (strncmp(buffer, "221 ", 4) == 0)
234 localstruct->state = SMTP_GOT_BYE;
235 else
236 here->retval = SYSM_BAD_RESP;
237 }
238 break;
239 }
240 case SMTP_GOT_BYE:
241 {
242 here->retval = SYSM_OK;
243 if (debug || here->checkent->trace)
244 print_err(here->checkent->trace, "smtp: returing a OK value");
245 break;
246 }
247 default:
248 {
249 print_err(1, "smtp.c: bug, how did we get here? localstruct->state = %d", localstruct->state);
250 break;
251 }
252 }
253 if (here->retval != -1)
254 {
255 /* insert cleanup code here */
256 close (here->filedes);
257 FREE(localstruct);
258 here->monitordata = NULL;
259 }
260 return;
261 }
262
263 void
stop_test_smtp(struct monitorent * here)264 stop_test_smtp(struct monitorent *here)
265 {
266 struct smtpdata *localstruct = NULL;
267
268 localstruct = here->monitordata;
269
270 if (localstruct == NULL)
271 return;
272
273 close(here->filedes);
274 FREE(localstruct);
275 here->monitordata = NULL;
276 return;
277
278 }
279
280