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