1 /* $Id: ssp_email.c,v 2.12 2008/04/26 19:50:56 fknobbe Exp $
2 *
3 *
4 * Copyright (c) 2002-2008 Frank Knobbe <frank@knobbe.us>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 *
29 * ssp_email.c
30 *
31 * Purpose:
32 *
33 * This SnortSam plugin sends an email with a notification of the block/unblock.
34 * It connects to a specified mail server and sends to a specified recipient via
35 * standard SMTP (not ESMTP) commands.
36 *
37 * AUTHENTICATION (AUTH) AND/OR ENCRYPTION (OVER SSL) IS NOT SUPPORTED.
38 * If you need to authenticate to your mail server, or prefer SMTP over SSL,
39 * please use a program like swatch to check for changes in the log file and
40 * have a third party mailer send them. (This is recommended for performance
41 * reasons anyway).
42 *
43 *
44 */
45
46
47 #ifndef __SSP_EMAIL_C__
48 #define __SSP_EMAIL_C__
49
50
51 #include "snortsam.h"
52 #include "ssp_email.h"
53
54 #include <sys/types.h>
55 #include <stdio.h>
56 #include <string.h>
57 #include <time.h>
58 #ifdef WIN32
59 #include <winsock.h>
60 #else
61 #include <netinet/in.h>
62 #include <arpa/inet.h>
63 #endif
64
65
66 extern unsigned int disablereverselookups;
67
68
69 /* This routine parses the email statements in the config file
70 * and builds a list of email servers/recipients.
71 */
EmailParse(char * val,char * file,unsigned long line,DATALIST * plugindatalist)72 void EmailParse(char *val,char *file,unsigned long line,DATALIST *plugindatalist)
73 { EMAILDATA *emailp;
74 char *p2,msg[STRBUFSIZE+2],*port=NULL;
75 struct in_addr emailip;
76
77 #ifdef FWSAMDEBUG
78 printf("Debug: [email] Plugin Parsing...\n");
79 #endif
80
81 if(*val)
82 { p2=val;
83 while(*p2 && !myisspace(*p2) && *p2!=':')
84 p2++;
85 if(*p2==':')
86 { *p2++ =0;
87 while(*p2==':' || myisspace(*p2))
88 p2++;
89 port=p2;
90 while(*p2 && !myisspace(*p2))
91 p2++;
92 }
93 *p2++ =0;
94
95 emailip.s_addr=getip(val);
96 if(emailip.s_addr) /* If we have a valid IP address */
97 { emailp=safemalloc(sizeof(EMAILDATA),"EmailParse","emailp"); /* create new email struct */
98 plugindatalist->data=emailp;
99 emailp->ip.s_addr=emailip.s_addr;
100 emailp->recipient[0]=emailp->sender[0]=0;
101 emailp->mailsocket=0;
102 emailp->loggedin=FALSE;
103 emailp->port=25;
104 if(port)
105 { if(atoi(port)>0)
106 emailp->port=atoi(port);
107 }
108
109 if(*p2)
110 { val=p2;
111 while(*val && myisspace(*val)) /* now parse the remaining text */
112 val++;
113 if(val)
114 { p2=val;
115 while(*p2 && !myisspace(*p2))
116 p2++;
117
118 if(*p2)
119 { *p2++ =0;
120 safecopy(emailp->recipient,val); /* save recipient */
121
122 val=p2;
123 while(*val && myisspace(*val)) /* has a sender name been specified? */
124 val++;
125 if(val)
126 { p2=val;
127 while(*p2 && !myisspace(*p2))
128 p2++;
129 *p2=0;
130 safecopy(emailp->sender,val); /* save sender */
131 }
132 }
133 else
134 { *p2=0;
135 safecopy(emailp->recipient,val); /* save recipient */
136 }
137 }
138 }
139 if(!emailp->recipient[0])
140 { snprintf(msg,sizeof(msg)-1,"Error: [%s: %lu] EMAIL defined without recipient!",file,line);
141 logmessage(1,msg,"email",0);
142 free(emailp);
143 plugindatalist->data=NULL;
144 }
145 }
146 else
147 { snprintf(msg,sizeof(msg)-1,"Error: [%s: %lu] Invalid EMAIL server '%s' ignored.",file,line,val);
148 logmessage(1,msg,"email",0);
149 }
150 }
151 else
152 { snprintf(msg,sizeof(msg)-1,"Error: [%s: %lu] Empty EMAIL parameter.",file,line);
153 logmessage(1,msg,"email",0);
154 }
155 }
156
157
158 /* This routine sends the email only on block events, not unblock
159 */
EmailSendBlockOnly(BLOCKINFO * bd,void * data,unsigned long qp)160 void EmailSendBlockOnly(BLOCKINFO *bd,void *data,unsigned long qp)
161 { if(bd->block)
162 EmailSend(bd,data,qp);
163 }
164
165 /* This routine sends the email
166 */
EmailSend(BLOCKINFO * bd,void * data,unsigned long qp)167 void EmailSend(BLOCKINFO *bd,void *data,unsigned long qp)
168 { EMAILDATA *emailp;
169 struct sockaddr_in thissocketaddr,emailsocketaddr;
170 unsigned long ll;
171 char emailmsg[4000],serverat[STRBUFSIZE+2],edate[42],msg[STRBUFSIZE+2],msg2[STRBUFSIZE+2],host[STRBUFSIZE+2];
172 struct tm *timep;
173 signed int timediff,gth;
174 struct protoent *protoe;
175 time_t notetime;
176 #ifdef FWSAMDEBUG
177 #ifdef WIN32
178 unsigned long threadid=GetCurrentThreadId();
179 #else
180 pthread_t threadid=pthread_self();
181 #endif
182 #endif
183
184 if(!data)
185 return;
186 emailp=(EMAILDATA *)data;
187
188 #ifdef FWSAMDEBUG
189 printf("Debug: [email][%lx] Plugin Sending Mail...\n",(unsigned long)threadid);
190 #endif
191
192 notetime=bd->blocktime;
193 if(!bd->block)
194 notetime+=bd->duration;
195 timep=gmtime((time_t *)&(notetime));
196 gth=timep->tm_hour;
197 timep=localtime((time_t *)&(notetime));
198 strftime(edate,40,"%a, %d %b %Y %H:%M:%S",timep);
199 timediff=timep->tm_hour-gth;
200 if(timediff>12)
201 timediff-=24;
202 else if(timediff<-12)
203 timediff+=24;
204
205 snprintf(serverat,sizeof(serverat)-1,"mail server at %s",inettoa(emailp->ip.s_addr));
206
207 if(!emailp->mailsocket)
208 { emailsocketaddr.sin_port=htons(emailp->port);
209 emailsocketaddr.sin_addr.s_addr=emailp->ip.s_addr;
210 emailsocketaddr.sin_family=AF_INET;
211 thissocketaddr.sin_port=htons(0); /* get a dynamic port */
212 thissocketaddr.sin_addr.s_addr=0;
213 thissocketaddr.sin_family=AF_INET;
214 /* create socket */
215 emailp->mailsocket=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
216 if(emailp->mailsocket==INVALID_SOCKET)
217 { snprintf(emailmsg,sizeof(emailmsg)-1,"Error: [email] Couldn't create socket!");
218 logmessage(1,emailmsg,"email",emailp->ip.s_addr);
219 emailp->mailsocket=0;
220 return;
221 }
222 /* bind it */
223 if(bind(emailp->mailsocket,(struct sockaddr *)&(thissocketaddr),sizeof(struct sockaddr)))
224 { snprintf(emailmsg,sizeof(emailmsg)-1,"Error: [email] Couldn't bind socket!");
225 logmessage(1,emailmsg,"email",emailp->ip.s_addr);
226 emailp->mailsocket=0;
227 return;
228 }
229 /* and connect to mail server */
230 if(connect(emailp->mailsocket,(struct sockaddr *)&emailsocketaddr,sizeof(struct sockaddr)))
231 { snprintf(emailmsg,sizeof(emailmsg)-1,"Error: [email] Could not connect to %s! Will try later.",serverat);
232 logmessage(1,emailmsg,"email",emailp->ip.s_addr);
233 closesocket(emailp->mailsocket);
234 emailp->mailsocket=0;
235 }
236 }
237
238 if(emailp->mailsocket)
239 { do
240 {
241 #ifdef FWSAMDEBUG
242 printf("Debug: [email][%lx] Connected to %s.\n",(unsigned long)threadid,serverat);
243 #endif
244 ll=1;
245 ioctlsocket(emailp->mailsocket,FIONBIO,&ll); /* set non blocking */
246
247 ll=FALSE;
248
249 if(!emailp->loggedin)
250 {
251 if(!sendreceive(emailp->mailsocket,EMAILNETWAIT,"email",emailp->ip,"","220","waiting for banner on ",serverat))
252 { ll=TRUE;
253 continue;
254 }
255 snprintf(emailmsg,sizeof(emailmsg)-1,"HELO %s\r\n",myhostname); /* send helo */
256 if(!sendreceive(emailp->mailsocket,EMAILNETWAIT,"email",emailp->ip,emailmsg,"250","after HELO on ",serverat))
257 { ll=TRUE;
258 continue;
259 }
260 emailp->loggedin=TRUE;
261 }
262 snprintf(emailmsg,sizeof(emailmsg)-1,"RSET\r\n"); /* send reset */
263 if(!sendreceive(emailp->mailsocket,EMAILNETWAIT,"email",emailp->ip,emailmsg,"250","after RSET on ",serverat))
264 { ll=TRUE;
265 continue;
266 }
267 if(emailp->sender[0])
268 snprintf(emailmsg,sizeof(emailmsg)-1,"MAIL FROM:<%s>\r\n",emailp->sender); /* send mail from */
269 else
270 snprintf(emailmsg,sizeof(emailmsg)-1,"MAIL FROM:<SnortSam@%s>\r\n",myhostname); /* send mail from */
271 if(!sendreceive(emailp->mailsocket,EMAILNETWAIT,"email",emailp->ip,emailmsg,"250","after MAIL FROM on ",serverat))
272 { ll=TRUE;
273 continue;
274 }
275 snprintf(emailmsg,sizeof(emailmsg)-1,"RCPT TO:<%s>\r\n",emailp->recipient); /* send rcpt to */
276 if(!sendreceive(emailp->mailsocket,EMAILNETWAIT,"email",emailp->ip,emailmsg,"250","after RCPT TO on ",serverat))
277 { ll=TRUE;
278 continue;
279 }
280 snprintf(emailmsg,sizeof(emailmsg)-1,"DATA\r\n"); /* send reset */
281 if(!sendreceive(emailp->mailsocket,EMAILNETWAIT,"email",emailp->ip,emailmsg,"354","after DATA on ",serverat))
282 { ll=TRUE;
283 continue;
284 }
285
286 if(disablereverselookups)
287 snprintf(host,sizeof(host)-1,"%s",inettoa(bd->blockip));
288 else
289 snprintf(host,sizeof(host)-1,"%s (%s)",inettoa(bd->blockip),gethstname(bd->blockip));
290
291 if(bd->block)
292 { switch(bd->mode&FWSAM_HOW)
293 { case FWSAM_HOW_THIS:
294 protoe=getprotobynumber(bd->proto);
295 snprintf(msg,sizeof(msg)-1, "Blocking host %s in connection %s->%s:%d (%s) for %lu seconds.",
296 host,bd->mode&FWSAM_WHO_SRC?inettoa(bd->blockip):inettoa(bd->peerip),bd->mode&FWSAM_WHO_SRC?inettoa(bd->peerip):inettoa(bd->blockip),bd->port,protoe->p_name,(unsigned long)bd->duration);
297 break;
298 case FWSAM_HOW_IN:
299 snprintf(msg,sizeof(msg)-1, "Blocking host %s inbound for %lu seconds.",host,(unsigned long)bd->duration);
300 break;
301 case FWSAM_HOW_OUT:
302 snprintf(msg,sizeof(msg)-1, "Blocking host %s outbound for %lu seconds.",host,(unsigned long)bd->duration);
303 break;
304 case FWSAM_HOW_INOUT:
305 snprintf(msg,sizeof(msg)-1, "Blocking host %s completely for %lu seconds.",host,(unsigned long)bd->duration);
306 break;
307 default:
308 snprintf(msg,sizeof(msg)-1, "Blocking host %s in a weird way for %lu seconds. (Let me know if you see this message!)",host,(unsigned long)bd->duration);
309 break;
310 }
311 snprintf(msg2,sizeof(msg2)-1,"This block was triggered by signature ID: %lu",bd->sig_id);
312 snprintf(emailmsg,sizeof(emailmsg)-1,"From: %s%s\r\nTo: %s\r\nSubject: Blocked IP Address %s\r\nDate: %s %+.2i00\r\n\r\n%s\r\n\r\n%s\r\n\r\n.\r\n",
313 emailp->sender[0]?emailp->sender:"SnortSam@",emailp->sender[0]?"":myhostname,emailp->recipient,
314 inettoa(bd->blockip),edate,timediff,msg,msg2); /* send message */
315 }
316 else
317 { switch(bd->mode&FWSAM_HOW)
318 { case FWSAM_HOW_THIS:
319 protoe=getprotobynumber(bd->proto);
320 snprintf(msg,sizeof(msg)-1, "Removing %lu sec block for host %s in connection %s->%s:%d (%s).",
321 (unsigned long)bd->duration,host,bd->mode&FWSAM_WHO_SRC?inettoa(bd->blockip):inettoa(bd->peerip),bd->mode&FWSAM_WHO_SRC?inettoa(bd->peerip):inettoa(bd->blockip),bd->port,protoe->p_name);
322 break;
323 case FWSAM_HOW_IN:
324 snprintf(msg,sizeof(msg)-1, "Removing %lu sec inbound block for host %s.",(unsigned long)bd->duration,host);
325 break;
326 case FWSAM_HOW_OUT:
327 snprintf(msg,sizeof(msg)-1, "Removing %lu sec outbound block for host %s.",(unsigned long)bd->duration,host);
328 break;
329 case FWSAM_HOW_INOUT:
330 snprintf(msg,sizeof(msg)-1, "Removing %lu sec complete block for host %s.",(unsigned long)bd->duration,host);
331 break;
332 default:
333 snprintf(msg,sizeof(msg)-1, "Removing weird %lu sec block for host %s.",(unsigned long)bd->duration,host);
334 break;
335 }
336 snprintf(msg2,sizeof(msg2)-1,"The block was originally triggered by signature ID: %lu",bd->sig_id);
337 snprintf(emailmsg,sizeof(emailmsg)-1,"From: %s%s\r\nTo: %s\r\nSubject: Unblocked IP Address %s\r\nDate: %s %+.2i00\r\n\r\n%s\r\n\r\n%s\r\n\r\n.\r\n",
338 emailp->sender[0]?emailp->sender:"SnortSam@",emailp->sender[0]?"":myhostname,emailp->recipient,
339 inettoa(bd->blockip),edate,timediff,msg,msg2); /* send message */
340 }
341 if(!sendreceive(emailp->mailsocket,EMAILNETWAIT,"email",emailp->ip,emailmsg,"250","after message on ",serverat))
342 { ll=TRUE;
343 continue;
344 }
345
346 if(!moreinqueue(qp))
347 { snprintf(emailmsg,sizeof(emailmsg)-1,"QUIT\r\n"); /* send reset */
348 sendreceive(emailp->mailsocket,EMAILNETWAIT,"email",emailp->ip,emailmsg,"","after QUIT on ",serverat);
349 ll=TRUE;
350 }
351 }while(FALSE);
352
353 if(ll)
354 { closesocket(emailp->mailsocket);
355 emailp->mailsocket=0;
356 emailp->loggedin=FALSE;
357 }
358 }
359
360 #ifdef FWSAMDEBUG
361 printf("Debug: [email][%lx] Email has been sent. Now waiting 10 secs...\n",(unsigned long)threadid);
362 waitms(10000);
363 printf("Debug: Done waiting... ending thread %lx.\n",(unsigned long)threadid);
364 #endif
365 }
366
367 #endif /* __SSP_EMAIL_C__ */
368
369
370
371
372
373
374