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