1 /* $Id: ssp_pix.c,v 2.9 2008/04/26 19:50:01 fknobbe Exp $
2 *
3 *
4 * Copyright (c) 2002-2004 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 * Acknowledgements:
29 *
30 * Thanks to Aaron Carr for letting me use his PIX and making test machines
31 * accessible.
32 *
33 *
34 *
35 * ssp_pix.c
36 *
37 * Purpose:
38 *
39 * This SnortSam plugin telnet's into one or more Cisco PIX firewalls,
40 * and issues the shun command. SnortSam will also expire the blocks
41 * itself since the PIX does not have automatic time-out functionality.
42 *
43 * Comments:
44 *
45 * Even though the SHUN command has options for peerip, port and protocol,
46 * in my tests this didn't work. It would still block the whole IP.
47 * SnortSam will default to the whole IP and not even attempt to
48 * send peer, port, and protocol information.
49 *
50 * Is this a bug in the PIX? This can be revisited lated.
51 *
52 * UPDATE: I think I know why the service didn't work in my tests.
53 * I entered the protocol as 6 (and 17) instead of tcp (and udp).
54 * My guess is that the PIX was expecting tcp, couldn't interpret
55 * 7 and just blocked the whole IP. NEED TO TRY THIS AGAIN.
56 *
57 * UPDATE: Tried it again. The problem is that the PIX only accepts one
58 * connection per IP. Also, there is no specific (IP/service pair)
59 * unshunning of IPs. That means full IP blocks will remain the default
60 * until something changes in the PIX IOS to support specific connection
61 * shuns.
62 *
63 *
64 */
65
66
67 #ifndef __SSP_PIX_C__
68 #define __SSP_PIX_C__
69
70
71 #include "snortsam.h"
72 #include "ssp_pix.h"
73
74
75 #include <sys/types.h>
76 #include <stdio.h>
77 #include <string.h>
78 #include <time.h>
79 #ifdef WIN32
80 #include <winsock.h>
81 #else
82 #include <netinet/in.h>
83 #include <arpa/inet.h>
84 #endif
85
86
87
88
89 /* This routine parses the pix statements in the config file.
90 * It builds a list of pixes)
91 */
PIXParse(char * val,char * file,unsigned long line,DATALIST * plugindatalist)92 void PIXParse(char *val,char *file,unsigned long line,DATALIST *plugindatalist)
93 { PIXDATA *pixp;
94 char *p2,msg[STRBUFSIZE+2],*p3;
95 struct in_addr pixip;
96
97 #ifdef FWSAMDEBUG
98 printf("Debug: [pix] Plugin Parsing...\n");
99 #endif
100
101 if(*val)
102 { p2=val;
103 while(*p2 && !myisspace(*p2))
104 p2++;
105 if(*p2)
106 *p2++ =0;
107 pixip.s_addr=getip(val);
108 if(pixip.s_addr) /* If we have a valid IP address */
109 { pixp=safemalloc(sizeof(PIXDATA),"PIXParse","pixp"); /* create new pix */
110 plugindatalist->data=pixp;
111 pixp->ip.s_addr=pixip.s_addr;
112 pixp->pixsocket=0;
113 pixp->loggedin=FALSE;
114 pixp->username[0]=pixp->enablepw[0]=pixp->userlogin=0;
115 pixp->telnetpw=pixp->username;
116
117 if(*p2)
118 { val=p2;
119 while(*val && myisspace(*val)) /* now parse the remaining text */
120 val++;
121 if(val)
122 { p2=val;
123 while(*p2 && !myisspace(*p2))
124 p2++;
125 if(*p2)
126 *p2++ =0;
127 safecopy(pixp->username,val); /* save telnet password */
128
129 p3=strchr(pixp->username,'/'); /* Check if a username is given */
130 if(p3)
131 { *p3++ =0;
132 pixp->telnetpw=p3;
133 pixp->userlogin=TRUE;
134 }
135
136 if(*p2) /* if we have a second password */
137 { while(*p2 && myisspace(*p2))
138 p2++;
139 safecopy(pixp->enablepw,p2);/* it would be the enable password */
140 }
141 else
142 safecopy(pixp->enablepw,pixp->telnetpw); /* if only one password was found, use it for both */
143 }
144 }
145 if(!pixp->telnetpw[0])
146 { snprintf(msg,sizeof(msg)-1,"Error: [%s: %lu] PIX defined without passwords!",file,line);
147 logmessage(1,msg,"pix",0);
148 free(pixp);
149 plugindatalist->data=NULL;
150 }
151 #ifdef FWSAMDEBUG
152 else
153 printf("Debug: [pix] Adding PIX: IP \"%s\", PW \"%s\", EN \"%s\"\n",inettoa(pixp->ip.s_addr),pixp->telnetpw,pixp->enablepw);
154 #endif
155 }
156 else
157 { snprintf(msg,sizeof(msg)-1,"Error: [%s: %lu] Invalid PIX parameter '%s' ignored.",file,line,val);
158 logmessage(1,msg,"pix",0);
159 }
160 }
161 else
162 { snprintf(msg,sizeof(msg)-1,"Error: [%s: %lu] Empty PIX parameter.",file,line);
163 logmessage(1,msg,"pix",0);
164 }
165 }
166
167
168 /* This routine initiates the block. It walks the list of PIX'es
169 * telnet's in, and issues the shun command.
170 */
PIXBlock(BLOCKINFO * bd,void * data,unsigned long qp)171 void PIXBlock(BLOCKINFO *bd,void *data,unsigned long qp)
172 { PIXDATA *pixp;
173 struct sockaddr_in thissocketaddr,pixsocketaddr;
174 unsigned long flag;
175 char pixmsg[STRBUFSIZE+1],pixat[STRBUFSIZE+1];
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 pixp=(PIXDATA *)data;
187
188 #ifdef FWSAMDEBUG
189 printf("Debug: [pix][%lx] Plugin Blocking...\n",(unsigned long)threadid);
190 #endif
191
192 snprintf(pixat,sizeof(pixat)-1,"PIX at %s",inettoa(pixp->ip.s_addr));
193
194 if(!pixp->pixsocket)
195 { pixsocketaddr.sin_port=htons(23); /* telnet */
196 pixsocketaddr.sin_addr.s_addr=pixp->ip.s_addr;
197 pixsocketaddr.sin_family=AF_INET;
198
199 thissocketaddr.sin_port=htons(0); /* get a dynamic port */
200 thissocketaddr.sin_addr.s_addr=0;
201 thissocketaddr.sin_family=AF_INET;
202
203 /* create socket */
204 pixp->pixsocket=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
205 if(pixp->pixsocket==INVALID_SOCKET)
206 { snprintf(pixmsg,sizeof(pixmsg)-1,"Error: [pix] Couldn't create socket!");
207 logmessage(1,pixmsg,"pix",pixp->ip.s_addr);
208 pixp->pixsocket=0;
209 return;
210 }
211 /* bind it */
212 if(bind(pixp->pixsocket,(struct sockaddr *)&(thissocketaddr),sizeof(struct sockaddr)))
213 { snprintf(pixmsg,sizeof(pixmsg)-1,"Error: [pix] Couldn't bind socket!");
214 logmessage(1,pixmsg,"pix",pixp->ip.s_addr);
215 pixp->pixsocket=0;
216 return;
217 }
218 /* and connect to pix */
219 if(connect(pixp->pixsocket,(struct sockaddr *)&pixsocketaddr,sizeof(struct sockaddr)))
220 { snprintf(pixmsg,sizeof(pixmsg)-1,"Error: [pix] Could not connect to %s! Will try later.",pixat);
221 logmessage(1,pixmsg,"pix",pixp->ip.s_addr);
222 closesocket(pixp->pixsocket);
223 pixp->pixsocket=0;
224 }
225 }
226 if(pixp->pixsocket)
227 { do
228 {
229 #ifdef FWSAMDEBUG
230 printf("Debug: [pix][%lx] Connected to %s.\n",(unsigned long)threadid,pixat);
231 #endif
232 flag=-1;
233 ioctlsocket(pixp->pixsocket,FIONBIO,&flag); /* set non blocking */
234 flag=FALSE;
235
236 if(!pixp->loggedin)
237 {
238 if(pixp->userlogin)
239 { if(!sendreceive(pixp->pixsocket,PIXNETWAIT,"pix",pixp->ip,"","username","waiting for user logon prompt from ",pixat))
240 { flag=TRUE;
241 continue;
242 }
243 snprintf(pixmsg,sizeof(pixmsg)-1,"%s\r",pixp->username); /* send username password */
244
245 if(!sendreceive(pixp->pixsocket,PIXNETWAIT,"pix",pixp->ip,pixmsg,"pass","at password prompt from ",pixat))
246 { flag=TRUE;
247 continue;
248 }
249 snprintf(pixmsg,sizeof(pixmsg)-1,"%s\r",pixp->telnetpw); /* send telnet password */
250 }
251 else
252 { if(!sendreceive(pixp->pixsocket,PIXNETWAIT,"pix",pixp->ip,"","pass","waiting for logon prompt from ",pixat))
253 { flag=TRUE;
254 continue;
255 }
256 snprintf(pixmsg,sizeof(pixmsg)-1,"%s\r",pixp->telnetpw); /* send telnet password */
257 }
258
259 if(!sendreceive(pixp->pixsocket,PIXNETWAIT,"pix",pixp->ip,pixmsg,"> ","at logon prompt of ",pixat))
260 { flag=TRUE;
261 continue;
262 }
263 /* send enable */
264 if(!sendreceive(pixp->pixsocket,PIXNETWAIT,"pix",pixp->ip,"enable\r","pass","at enable command of ",pixat))
265 { flag=TRUE;
266 continue;
267 }
268
269 snprintf(pixmsg,sizeof(pixmsg)-1,"%s\r",pixp->enablepw); /* send enable password */
270 if(!sendreceive(pixp->pixsocket,PIXNETWAIT,"pix",pixp->ip,pixmsg,"# ","at enable prompt of ",pixat))
271 { flag=TRUE;
272 continue;
273 }
274 pixp->loggedin=TRUE;
275 }
276 /* send shun command with IP only (see comments section on top of source) */
277 snprintf(pixmsg,sizeof(pixmsg)-1,"%sshun %s\r",bd->block?"":"no ",inettoa(bd->blockip));
278 if(!sendreceive(pixp->pixsocket,PIXNETWAIT,"pix",pixp->ip,pixmsg,"# ","at shun command of ",pixat))
279 { flag=TRUE;
280 continue;
281 }
282
283 if(!moreinqueue(qp))
284 { sendreceive(pixp->pixsocket,PIXNETWAIT,"pix",pixp->ip,"quit\r","","at quit command of ",pixat);
285 flag=TRUE;
286 }
287 }while(FALSE);
288
289 if(flag)
290 { closesocket(pixp->pixsocket);
291 pixp->pixsocket=0;
292 pixp->loggedin=FALSE;
293 }
294 }
295 }
296
297 #endif /* __SSP_PIX_C__ */
298
299
300
301
302
303
304