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