1 /*
2 * ModSecurity for Apache 2.x, http://www.modsecurity.org/
3 * Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
4 *
5 * You may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * If any of the files related to licensing are missing or if you have any
11 * other questions related to licensing please contact Trustwave Holdings, Inc.
12 * directly using the email address security@modsecurity.org.
13 */
14 
15 //#undef inline
16 #define	inline inline
17 
18 #include <stdio.h>
19 #include <conio.h>
20 #include "api.h"
21 
22 
23 char *config_file = NULL;
24 char *url_file = NULL;
25 char *event_files[1024];
26 int event_file_cnt;
27 char *event_file = NULL;
28 int event_file_len = 0;
29 char **event_file_lines;
30 int event_line_cnt = 0;
31 int event_file_blocks[256];
32 
33 #define	EVENT_FILE_MAX_SIZE		(16*1024*1024)
34 
35 #define	MAX_URLS	4096
36 
37 char urls[MAX_URLS][4096];
38 int url_cnt = 0;
39 
readeventfile(char * name)40 void readeventfile(char *name)
41 {
42 	if(event_file == NULL)
43 	{
44 		event_file = (char *)malloc(EVENT_FILE_MAX_SIZE);
45 		event_file_lines = (char **)malloc(EVENT_FILE_MAX_SIZE);
46 	}
47 
48 	event_file_len = 0;
49 	event_line_cnt = 0;
50 	memset(event_file_blocks, -1, sizeof(int) * 256);
51 
52 	FILE *fr = fopen(name, "rb");
53 
54 	if(fr == NULL)
55 		return;
56 
57 	event_file_len = fread(event_file, 1, EVENT_FILE_MAX_SIZE - 1, fr);
58 
59 	fclose(fr);
60 
61 	event_file[event_file_len] = 0;
62 }
63 
parseeventfile()64 void parseeventfile()
65 {
66 	if(event_file_len == 0 || event_file == NULL)
67 		return;
68 
69 	char *t = event_file;
70 	char *e = event_file + event_file_len;
71 	int nocrlf = 1;
72 
73 	while(t < e)
74 	{
75 		event_file_lines[event_line_cnt++] = t;
76 
77 		while(t < e && *t != 10 && *t != 13)
78 			t++;
79 
80 		char ct = *t;
81 		*t = 0;
82 		int i = event_line_cnt - 1;
83 
84 		int l = strlen(event_file_lines[i]);
85 
86 		if(l == 14 && event_file_lines[i][0] == '-' && event_file_lines[i][1] == '-' && event_file_lines[i][l-2] == '-' && event_file_lines[i][l-1] == '-')
87 		{
88 			char blk =  event_file_lines[i][l-3];
89 
90 			event_file_blocks[blk] = i;
91 
92 			if(blk == 'C' || blk == 'G')
93 			{
94 				nocrlf = 0;
95 			}
96 			else
97 			{
98 				nocrlf = 1;
99 			}
100 		}
101 		*t = ct;
102 
103 		if(nocrlf)
104 			while(t < e && (*t == 10 || *t == 13))
105 				*t++ = 0;
106 		else
107 			while(t < e && (*t == 10 || *t == 13))
108 				t++;
109 	}
110 }
111 
parseargs(int argc,char * argv[])112 void parseargs(int argc, char *argv[])
113 {
114 	int i = 1;
115 
116 	event_file_cnt = 0;
117 
118 	while(i < argc)
119 	{
120 		if(argv[i][0] == '-')
121 		{
122 			if(argv[i][1] == 'c' && i < argc - 1)
123 			{
124 				config_file = argv[i + 1];
125 				i += 2;
126 				continue;
127 			}
128 			if(argv[i][1] == 'u' && i < argc - 1)
129 			{
130 				url_file = argv[i + 1];
131 				i += 2;
132 				continue;
133 			}
134 			i++;
135 			continue;
136 		}
137 		if(event_file_cnt == 1024)
138 		{
139 			fprintf(stderr, "Too many input files! (limit 1024)\n");
140 			break;
141 		}
142 
143 		event_files[event_file_cnt++] = argv[i++];
144 	}
145 }
146 
log(void * obj,int level,char * str)147 void log(void *obj, int level, char *str)
148 {
149 	printf("%s\n", str);
150 }
151 
152 unsigned int bodypos = 0;
153 
readbody(request_rec * r,char * buf,unsigned int length,unsigned int * readcnt,int * is_eos)154 apr_status_t readbody(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
155 {
156 	int j = event_file_blocks['C'];
157 
158 	if(j < 0)
159 	{
160 		*is_eos = 1;
161 		return APR_SUCCESS;
162 	}
163 
164 	j++;
165 
166 	if(event_file_lines[j][0] == 0)
167 	{
168 		*is_eos = 1;
169 		return APR_SUCCESS;
170 	}
171 
172 	unsigned int l = strlen(event_file_lines[j]);
173 	unsigned int size = length;
174 
175 	if(bodypos + size > l)
176 		size = l - bodypos;
177 
178 	memcpy(buf, &event_file_lines[j][bodypos], size);
179 
180 	bodypos += size;
181 	*readcnt = size;
182 
183 	if(bodypos == l)
184 	{
185 		*is_eos = 1;
186 	}
187 
188 	return APR_SUCCESS;
189 }
190 
191 unsigned int responsepos = 0;
192 
readresponse(request_rec * r,char * buf,unsigned int length,unsigned int * readcnt,int * is_eos)193 apr_status_t readresponse(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
194 {
195 	int j = event_file_blocks['G'];
196 
197 	if(j < 0)
198 	{
199 		*is_eos = 1;
200 		return APR_SUCCESS;
201 	}
202 
203 	j++;
204 
205 	if(event_file_lines[j][0] == 0)
206 	{
207 		*is_eos = 1;
208 		return APR_SUCCESS;
209 	}
210 
211 	unsigned int l = strlen(event_file_lines[j]);
212 	unsigned int size = length;
213 
214 	if(responsepos + size > l)
215 		size = l - responsepos;
216 
217 	memcpy(buf, &event_file_lines[j][responsepos], size);
218 
219 	responsepos += size;
220 	*readcnt = size;
221 
222 	if(responsepos == l)
223 		*is_eos = 1;
224 
225 	return APR_SUCCESS;
226 }
227 
main(int argc,char * argv[])228 void main(int argc, char *argv[])
229 {
230 	directory_config *config;
231 	conn_rec *c;
232 	request_rec *r;
233 
234 	parseargs(argc, argv);
235 
236 	if(config_file == NULL || argc < 3)
237 	{
238 		printf("Usage:\n");
239 		printf("standalone.exe -c <config_file> [-u <text_file_with_urls>] <event_file1> [<event_file2> <event_file3> ...]\n");
240 		return;
241 	}
242 
243 	modsecSetLogHook(NULL, log);
244 
245 	modsecSetReadBody(readbody);
246 	modsecSetReadResponse(readresponse);
247 
248 	modsecInit();
249 
250 	modsecStartConfig();
251 
252 	config = modsecGetDefaultConfig();
253 
254 	const char * err = modsecProcessConfig(config, config_file, "c:\\inetpub\\wwwroot");
255 
256 	if(err != NULL)
257 	{
258 		printf("%s\n", err);
259 	}
260 
261 	modsecFinalizeConfig();
262 
263 	modsecInitProcess();
264 
265 	if(url_file != NULL)
266 	{
267 		FILE *fr = fopen(url_file, "rb");
268 		int i = 0;
269 
270 		while(fgets(urls[i],4096,fr) != NULL)
271 		{
272 			urls[i][4095] = 0;
273 
274 			int l = strlen(urls[i]) - 1;
275 
276 			if(l < 8)
277 				continue;
278 
279 			while(urls[i][l] == 10 || urls[i][l] == 13)
280 				l--;
281 
282 			urls[i++][l + 1] = 0;
283 		}
284 
285 		url_cnt = i;
286 		fclose(fr);
287 	}
288 
289 	for(int i = 0; i < event_file_cnt; i++)
290 	{
291 		if(url_cnt == 0)
292 		{
293 			urls[0][0] = 0;
294 			url_cnt = 1;
295 		}
296 
297 		for(int ui = 0; ui < url_cnt; ui++)
298 		{
299 			readeventfile(event_files[i]);
300 			parseeventfile();
301 
302 			bodypos = 0;
303 			responsepos = 0;
304 
305 			c = modsecNewConnection();
306 
307 			modsecProcessConnection(c);
308 
309 			r = modsecNewRequest(c, config);
310 
311 			int j = event_file_blocks['B'];
312 
313 			if(j < 0)
314 				continue;
315 
316 			j++;
317 
318 			if(event_file_lines[j][0] == 0)
319 				continue;
320 
321 			char *method = event_file_lines[j];
322 			char *url = strchr(method, 32);
323 			char *proto = strchr(url + 1, 32);
324 
325 			if(url == NULL || proto == NULL)
326 				continue;
327 
328 			*url++=0;
329 			*proto++=0;
330 
331 			if(urls[ui][0] != 0)
332 			{
333 				url = urls[ui];
334 			}
335 
336 #define	SETMETHOD(m) if(strcmp(method,#m) == 0){ r->method = method; r->method_number = M_##m; }
337 
338 			r->method = "INVALID";
339 			r->method_number = M_INVALID;
340 
341 			SETMETHOD(OPTIONS)
342 			SETMETHOD(GET)
343 			SETMETHOD(POST)
344 			SETMETHOD(PUT)
345 			SETMETHOD(DELETE)
346 			SETMETHOD(TRACE)
347 			SETMETHOD(CONNECT)
348 			SETMETHOD(MOVE)
349 			SETMETHOD(COPY)
350 			SETMETHOD(PROPFIND)
351 			SETMETHOD(PROPPATCH)
352 			SETMETHOD(MKCOL)
353 			SETMETHOD(LOCK)
354 			SETMETHOD(UNLOCK)
355 
356 			r->protocol = proto;
357 
358 			while(event_file_lines[++j][0] != 0)
359 			{
360 				char *value = strchr(event_file_lines[j], ':');
361 
362 				if(value == NULL)
363 					break;
364 
365 				*value++ = 0;
366 
367 				while(*value <=32 && *value != 0)
368 					value++;
369 
370 				apr_table_setn(r->headers_in, event_file_lines[j], value);
371 			}
372 
373 			r->content_encoding = apr_table_get(r->headers_in, "Content-Encoding");
374 			r->content_type = apr_table_get(r->headers_in, "Content-Type");
375 			r->hostname = apr_table_get(r->headers_in, "Host");
376 			r->path_info = url;
377 
378 			char *query = strchr(url, '?');
379 			char *rawurl = url;
380 
381 			if(query != NULL)
382 			{
383 				rawurl = (char *)apr_palloc(r->pool, strlen(url) + 1);
384 				strcpy(rawurl, url);
385 				*query++ = 0;
386 				r->args = query;
387 			}
388 
389 			const char *lng = apr_table_get(r->headers_in, "Content-Languages");
390 
391 			if(lng != NULL)
392 			{
393 				r->content_languages = apr_array_make(r->pool, 1, sizeof(const char *));
394 
395 				*(const char **)apr_array_push(r->content_languages) = lng;
396 			}
397 
398 			r->request_time = apr_time_now();
399 
400 			r->parsed_uri.scheme = "http";
401 			r->parsed_uri.path = r->path_info;
402 			r->parsed_uri.hostname = (char *)r->hostname;
403 			r->parsed_uri.is_initialized = 1;
404 			r->parsed_uri.port = 80;
405 			r->parsed_uri.port_str = "80";
406 			r->parsed_uri.query = r->args;
407 			r->parsed_uri.dns_looked_up = 0;
408 			r->parsed_uri.dns_resolved = 0;
409 			r->parsed_uri.password = NULL;
410 			r->parsed_uri.user = NULL;
411 			r->parsed_uri.fragment = NULL;
412 
413 			r->unparsed_uri = rawurl;
414 			r->uri = r->unparsed_uri;
415 
416 			r->the_request = (char *)apr_palloc(r->pool, strlen(r->method) + 1 + strlen(r->uri) + 1 + strlen(r->protocol) + 1);
417 
418 			strcpy(r->the_request, r->method);
419 			strcat(r->the_request, " ");
420 			strcat(r->the_request, r->uri);
421 			strcat(r->the_request, " ");
422 			strcat(r->the_request, r->protocol);
423 
424 			apr_table_setn(r->subprocess_env, "UNIQUE_ID", "1");
425 
426 			modsecProcessRequest(r);
427 			modsecProcessResponse(r);
428 			modsecFinishRequest(r);
429 		}
430 	}
431 
432 	modsecTerminate();
433 	getch();
434 }
435