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 #define WIN32_LEAN_AND_MEAN
16
17 #undef inline
18 #define inline inline
19
20 // IIS7 Server API header file
21 #include <Windows.h>
22 #include <sal.h>
23 #include <strsafe.h>
24 #include "httpserv.h"
25
26 // Project header files
27 #include "mymodule.h"
28 #include "mymodulefactory.h"
29
30 #include "api.h"
31 #include "moduleconfig.h"
32
33 #include "winsock2.h"
34
35
36 class REQUEST_STORED_CONTEXT : public IHttpStoredContext
37 {
38 public:
REQUEST_STORED_CONTEXT()39 REQUEST_STORED_CONTEXT()
40 {
41 m_pConnRec = NULL;
42 m_pRequestRec = NULL;
43 m_pHttpContext = NULL;
44 m_pProvider = NULL;
45 m_pResponseBuffer = NULL;
46 m_pResponseLength = 0;
47 m_pResponsePosition = 0;
48 }
49
~REQUEST_STORED_CONTEXT()50 ~REQUEST_STORED_CONTEXT()
51 {
52 FinishRequest();
53 }
54
55 // virtual
56 VOID
CleanupStoredContext(VOID)57 CleanupStoredContext(
58 VOID
59 )
60 {
61 FinishRequest();
62 delete this;
63 }
64
FinishRequest()65 void FinishRequest()
66 {
67 if(m_pRequestRec != NULL)
68 {
69 modsecFinishRequest(m_pRequestRec);
70 m_pRequestRec = NULL;
71 }
72 if(m_pConnRec != NULL)
73 {
74 modsecFinishConnection(m_pConnRec);
75 m_pConnRec = NULL;
76 }
77 }
78
79 conn_rec *m_pConnRec;
80 request_rec *m_pRequestRec;
81 IHttpContext *m_pHttpContext;
82 IHttpEventProvider *m_pProvider;
83 char *m_pResponseBuffer;
84 ULONGLONG m_pResponseLength;
85 ULONGLONG m_pResponsePosition;
86 };
87
88
89 //----------------------------------------------------------------------------
90
GetIpAddr(apr_pool_t * pool,PSOCKADDR pAddr)91 char *GetIpAddr(apr_pool_t *pool, PSOCKADDR pAddr)
92 {
93 const char *format = "%15[0-9.]:%5[0-9]";
94 char ip[16] = { 0 }; // ip4 addresses have max len 15
95 char port[6] = { 0 }; // port numbers are 16bit, ie 5 digits max
96
97 DWORD len = 50;
98 char *buf = (char *)apr_palloc(pool, len);
99
100 if(buf == NULL)
101 return "";
102
103 buf[0] = 0;
104
105 WSAAddressToString(pAddr, sizeof(SOCKADDR), NULL, buf, &len);
106
107 // test for IPV4 with port on the end
108 if (sscanf(buf, format, ip, port) == 2) {
109 // IPV4 but with port - remove the port
110 char* input = ":";
111 char* ipv4 = strtok(buf, input);
112 return ipv4;
113 }
114
115 return buf;
116 }
117
CopySockAddr(apr_pool_t * pool,PSOCKADDR pAddr)118 apr_sockaddr_t *CopySockAddr(apr_pool_t *pool, PSOCKADDR pAddr)
119 {
120 apr_sockaddr_t *addr = (apr_sockaddr_t *)apr_palloc(pool, sizeof(apr_sockaddr_t));
121 int adrlen = 16, iplen = 4;
122
123 if(pAddr->sa_family == AF_INET6)
124 {
125 adrlen = 46;
126 iplen = 16;
127 }
128
129 addr->addr_str_len = adrlen;
130 addr->family = pAddr->sa_family;
131
132 addr->hostname = "unknown";
133 #ifdef WIN32
134 addr->ipaddr_len = sizeof(IN_ADDR);
135 #else
136 addr->ipaddr_len = sizeof(struct in_addr);
137 #endif
138 addr->ipaddr_ptr = &addr->sa.sin.sin_addr;
139 addr->pool = pool;
140 addr->port = 80;
141 #ifdef WIN32
142 memcpy(&addr->sa.sin.sin_addr.S_un.S_addr, pAddr->sa_data, iplen);
143 #else
144 memcpy(&addr->sa.sin.sin_addr.s_addr, pAddr->sa_data, iplen);
145 #endif
146 addr->sa.sin.sin_family = pAddr->sa_family;
147 addr->sa.sin.sin_port = 80;
148 addr->salen = sizeof(addr->sa);
149 addr->servname = addr->hostname;
150
151 return addr;
152 }
153
154 //----------------------------------------------------------------------------
155
ZeroTerminate(const char * str,size_t len,apr_pool_t * pool)156 char *ZeroTerminate(const char *str, size_t len, apr_pool_t *pool)
157 {
158 char *_n = (char *)apr_palloc(pool, len + 1);
159
160 memcpy(_n, str, len);
161
162 _n[len] = 0;
163
164 return _n;
165 }
166
167 //----------------------------------------------------------------------------
168 // FUNCTION: ConvertUTF16ToUTF8
169 // DESC: Converts Unicode UTF-16 (Windows default) text to Unicode UTF-8.
170 //----------------------------------------------------------------------------
171
ConvertUTF16ToUTF8(__in const WCHAR * pszTextUTF16,size_t cchUTF16,apr_pool_t * pool)172 char *ConvertUTF16ToUTF8( __in const WCHAR * pszTextUTF16, size_t cchUTF16, apr_pool_t *pool )
173 {
174 //
175 // Special case of NULL or empty input string
176 //
177 if ( (pszTextUTF16 == NULL) || (*pszTextUTF16 == L'\0') || cchUTF16 == 0 )
178 {
179 // Return empty string
180 return "";
181 }
182
183 //
184 // Get size of destination UTF-8 buffer, in CHAR's (= bytes)
185 //
186 int cbUTF8 = ::WideCharToMultiByte(
187 CP_UTF8, // convert to UTF-8
188 0, // specify conversion behavior
189 pszTextUTF16, // source UTF-16 string
190 static_cast<int>( cchUTF16 ), // total source string length, in WCHAR's,
191 NULL, // unused - no conversion required in this step
192 0, // request buffer size
193 NULL, NULL // unused
194 );
195
196 if ( cbUTF8 == 0 )
197 {
198 return "";
199 }
200
201 //
202 // Allocate destination buffer for UTF-8 string
203 //
204
205 int cchUTF8 = cbUTF8; // sizeof(CHAR) = 1 byte
206
207 char *pszUTF8 = (char *)apr_palloc(pool, cchUTF8 + 1 );
208
209 //
210 // Do the conversion from UTF-16 to UTF-8
211 //
212 int result = ::WideCharToMultiByte(
213 CP_UTF8, // convert to UTF-8
214 0, // specify conversion behavior
215 pszTextUTF16, // source UTF-16 string
216 static_cast<int>( cchUTF16 ), // total source string length, in WCHAR's,
217 // including end-of-string \0
218 pszUTF8, // destination buffer
219 cbUTF8, // destination buffer size, in bytes
220 NULL, NULL // unused
221 );
222
223 if ( result == 0 )
224 {
225 return "";
226 }
227
228 pszUTF8[cchUTF8] = 0;
229
230 return pszUTF8;
231 }
232
Log(void * obj,int level,char * str)233 void Log(void *obj, int level, char *str)
234 {
235 CMyHttpModule *mod = (CMyHttpModule *)obj;
236 WORD logcat = EVENTLOG_INFORMATION_TYPE;
237
238 level &= APLOG_LEVELMASK;
239
240 if(level <= APLOG_ERR)
241 logcat = EVENTLOG_ERROR_TYPE;
242
243 if(level == APLOG_WARNING || strstr(str, "Warning.") != NULL)
244 logcat = EVENTLOG_WARNING_TYPE;
245
246 mod->WriteEventViewerLog(str, logcat);
247 }
248
249 #define NOTE_IIS "iis-tx-context"
250
StoreIISContext(request_rec * r,REQUEST_STORED_CONTEXT * rsc)251 void StoreIISContext(request_rec *r, REQUEST_STORED_CONTEXT *rsc)
252 {
253 apr_table_setn(r->notes, NOTE_IIS, (const char *)rsc);
254 }
255
RetrieveIISContext(request_rec * r)256 REQUEST_STORED_CONTEXT *RetrieveIISContext(request_rec *r)
257 {
258 REQUEST_STORED_CONTEXT *msr = NULL;
259 request_rec *rx = NULL;
260
261 /* Look in the current request first. */
262 msr = (REQUEST_STORED_CONTEXT *)apr_table_get(r->notes, NOTE_IIS);
263 if (msr != NULL) {
264 //msr->r = r;
265 return msr;
266 }
267
268 /* If this is a subrequest then look in the main request. */
269 if (r->main != NULL) {
270 msr = (REQUEST_STORED_CONTEXT *)apr_table_get(r->main->notes, NOTE_IIS);
271 if (msr != NULL) {
272 //msr->r = r;
273 return msr;
274 }
275 }
276
277 /* If the request was redirected then look in the previous requests. */
278 rx = r->prev;
279 while(rx != NULL) {
280 msr = (REQUEST_STORED_CONTEXT *)apr_table_get(rx->notes, NOTE_IIS);
281 if (msr != NULL) {
282 //msr->r = r;
283 return msr;
284 }
285 rx = rx->prev;
286 }
287
288 return NULL;
289 }
290
291
ReadFileChunk(HTTP_DATA_CHUNK * chunk,char * buf)292 HRESULT CMyHttpModule::ReadFileChunk(HTTP_DATA_CHUNK *chunk, char *buf)
293 {
294 OVERLAPPED ovl;
295 DWORD dwDataStartOffset;
296 ULONGLONG bytesTotal = 0;
297 BYTE * pIoBuffer = NULL;
298 HANDLE hIoEvent = INVALID_HANDLE_VALUE;
299 HRESULT hr = S_OK;
300
301 pIoBuffer = (BYTE *)VirtualAlloc(NULL,
302 1,
303 MEM_COMMIT | MEM_RESERVE,
304 PAGE_READWRITE);
305 if (pIoBuffer == NULL)
306 {
307 hr = HRESULT_FROM_WIN32(GetLastError());
308 goto Done;
309 }
310
311 hIoEvent = CreateEvent(NULL, // security attr
312 FALSE, // manual reset
313 FALSE, // initial state
314 NULL); // name
315 if (hIoEvent == NULL)
316 {
317 hr = HRESULT_FROM_WIN32(GetLastError());
318 goto Done;
319 }
320
321 while(bytesTotal < chunk->FromFileHandle.ByteRange.Length.QuadPart)
322 {
323 DWORD bytesRead = 0;
324 int was_eof = 0;
325 ULONGLONG offset = chunk->FromFileHandle.ByteRange.StartingOffset.QuadPart + bytesTotal;
326
327 ZeroMemory(&ovl, sizeof ovl);
328 ovl.hEvent = hIoEvent;
329 ovl.Offset = (DWORD)offset;
330 dwDataStartOffset = ovl.Offset & (m_dwPageSize - 1);
331 ovl.Offset &= ~(m_dwPageSize - 1);
332 ovl.OffsetHigh = offset >> 32;
333
334 if (!ReadFile(chunk->FromFileHandle.FileHandle,
335 pIoBuffer,
336 m_dwPageSize,
337 &bytesRead,
338 &ovl))
339 {
340 DWORD dwErr = GetLastError();
341
342 switch (dwErr)
343 {
344 case ERROR_IO_PENDING:
345 //
346 // GetOverlappedResult can return without waiting for the
347 // event thus leaving it signalled and causing problems
348 // with future use of that event handle, so just wait ourselves
349 //
350 WaitForSingleObject(ovl.hEvent, INFINITE); // == WAIT_OBJECT_0);
351
352 if (!GetOverlappedResult(
353 chunk->FromFileHandle.FileHandle,
354 &ovl,
355 &bytesRead,
356 TRUE))
357 {
358 dwErr = GetLastError();
359
360 switch(dwErr)
361 {
362 case ERROR_HANDLE_EOF:
363 was_eof = 1;
364 break;
365
366 default:
367 hr = HRESULT_FROM_WIN32(dwErr);
368 goto Done;
369 }
370 }
371 break;
372
373 case ERROR_HANDLE_EOF:
374 was_eof = 1;
375 break;
376
377 default:
378 hr = HRESULT_FROM_WIN32(dwErr);
379 goto Done;
380 }
381 }
382
383 bytesRead -= dwDataStartOffset;
384
385 if (bytesRead > chunk->FromFileHandle.ByteRange.Length.QuadPart)
386 {
387 bytesRead = (DWORD)chunk->FromFileHandle.ByteRange.Length.QuadPart;
388 }
389 if ((bytesTotal + bytesRead) > chunk->FromFileHandle.ByteRange.Length.QuadPart)
390 {
391 bytesRead = chunk->FromFileHandle.ByteRange.Length.QuadPart - bytesTotal;
392 }
393
394 memcpy(buf, pIoBuffer + dwDataStartOffset, bytesRead);
395
396 buf += bytesRead;
397 bytesTotal += bytesRead;
398
399 if(was_eof != 0)
400 chunk->FromFileHandle.ByteRange.Length.QuadPart = bytesTotal;
401 }
402
403 Done:
404 if(NULL != pIoBuffer)
405 {
406 VirtualFree(pIoBuffer, 0, MEM_RELEASE);
407 }
408
409 if(INVALID_HANDLE_VALUE != hIoEvent)
410 {
411 CloseHandle(hIoEvent);
412 }
413
414 return hr;
415 }
416
417 REQUEST_NOTIFICATION_STATUS
OnSendResponse(IN IHttpContext * pHttpContext,IN ISendResponseProvider * pResponseProvider)418 CMyHttpModule::OnSendResponse(
419 IN IHttpContext * pHttpContext,
420 IN ISendResponseProvider * pResponseProvider
421 )
422 {
423 REQUEST_STORED_CONTEXT *rsc = NULL;
424
425 rsc = (REQUEST_STORED_CONTEXT *)pHttpContext->GetModuleContextContainer()->GetModuleContext(g_pModuleContext);
426
427 EnterCriticalSection(&m_csLock);
428
429 // here we must check if response body processing is enabled
430 //
431 if(rsc == NULL || rsc->m_pRequestRec == NULL || rsc->m_pResponseBuffer != NULL || !modsecIsResponseBodyAccessEnabled(rsc->m_pRequestRec))
432 {
433 goto Exit;
434 }
435
436 HRESULT hr = S_OK;
437 IHttpResponse *pHttpResponse = NULL;
438 HTTP_RESPONSE *pRawHttpResponse = NULL;
439 HTTP_BYTE_RANGE *pFileByteRange = NULL;
440 HTTP_DATA_CHUNK *pSourceDataChunk = NULL;
441 LARGE_INTEGER lFileSize;
442 REQUEST_NOTIFICATION_STATUS ret = RQ_NOTIFICATION_CONTINUE;
443 ULONGLONG ulTotalLength = 0;
444 DWORD c;
445 request_rec *r = rsc->m_pRequestRec;
446
447 pHttpResponse = pHttpContext->GetResponse();
448 pRawHttpResponse = pHttpResponse->GetRawHttpResponse();
449
450 // here we must add handling of chunked response
451 // apparently IIS 7 calls this handler once per chunk
452 // see: http://stackoverflow.com/questions/4385249/how-to-buffer-and-process-chunked-data-before-sending-headers-in-iis7-native-mod
453
454 if(pRawHttpResponse->EntityChunkCount == 0)
455 goto Exit;
456
457 // here we must transfer response headers
458 //
459 USHORT ctcch = 0;
460 char *ct = (char *)pHttpResponse->GetHeader(HttpHeaderContentType, &ctcch);
461 char *ctz = ZeroTerminate(ct, ctcch, r->pool);
462
463 // assume HTML if content type not set
464 // without this output filter would not buffer response and processing would hang
465 //
466 if(ctz[0] == 0)
467 ctz = "text/html";
468
469 r->content_type = ctz;
470
471 #define _TRANSHEADER(id,str) if(pRawHttpResponse->Headers.KnownHeaders[id].pRawValue != NULL) \
472 {\
473 apr_table_setn(r->headers_out, str, \
474 ZeroTerminate(pRawHttpResponse->Headers.KnownHeaders[id].pRawValue, pRawHttpResponse->Headers.KnownHeaders[id].RawValueLength, r->pool)); \
475 }
476
477 _TRANSHEADER(HttpHeaderCacheControl, "Cache-Control");
478 _TRANSHEADER(HttpHeaderConnection, "Connection");
479 _TRANSHEADER(HttpHeaderDate, "Date");
480 _TRANSHEADER(HttpHeaderKeepAlive, "Keep-Alive");
481 _TRANSHEADER(HttpHeaderPragma, "Pragma");
482 _TRANSHEADER(HttpHeaderTrailer, "Trailer");
483 _TRANSHEADER(HttpHeaderTransferEncoding, "Transfer-Encoding");
484 _TRANSHEADER(HttpHeaderUpgrade, "Upgrade");
485 _TRANSHEADER(HttpHeaderVia, "Via");
486 _TRANSHEADER(HttpHeaderWarning, "Warning");
487 _TRANSHEADER(HttpHeaderAllow, "Allow");
488 _TRANSHEADER(HttpHeaderContentLength, "Content-Length");
489 _TRANSHEADER(HttpHeaderContentType, "Content-Type");
490 _TRANSHEADER(HttpHeaderContentEncoding, "Content-Encoding");
491 _TRANSHEADER(HttpHeaderContentLanguage, "Content-Language");
492 _TRANSHEADER(HttpHeaderContentLocation, "Content-Location");
493 _TRANSHEADER(HttpHeaderContentMd5, "Content-Md5");
494 _TRANSHEADER(HttpHeaderContentRange, "Content-Range");
495 _TRANSHEADER(HttpHeaderExpires, "Expires");
496 _TRANSHEADER(HttpHeaderLastModified, "Last-Modified");
497 _TRANSHEADER(HttpHeaderAcceptRanges, "Accept-Ranges");
498 _TRANSHEADER(HttpHeaderAge, "Age");
499 _TRANSHEADER(HttpHeaderEtag, "Etag");
500 _TRANSHEADER(HttpHeaderLocation, "Location");
501 _TRANSHEADER(HttpHeaderProxyAuthenticate, "Proxy-Authenticate");
502 _TRANSHEADER(HttpHeaderRetryAfter, "Retry-After");
503 _TRANSHEADER(HttpHeaderServer, "Server");
504 _TRANSHEADER(HttpHeaderSetCookie, "Set-Cookie");
505 _TRANSHEADER(HttpHeaderVary, "Vary");
506 _TRANSHEADER(HttpHeaderWwwAuthenticate, "Www-Authenticate");
507
508 #undef _TRANSHEADER
509
510 for(int i = 0; i < pRawHttpResponse->Headers.UnknownHeaderCount; i++)
511 {
512 apr_table_setn(r->headers_out,
513 ZeroTerminate(pRawHttpResponse->Headers.pUnknownHeaders[i].pName, pRawHttpResponse->Headers.pUnknownHeaders[i].NameLength, r->pool),
514 ZeroTerminate(pRawHttpResponse->Headers.pUnknownHeaders[i].pRawValue, pRawHttpResponse->Headers.pUnknownHeaders[i].RawValueLength, r->pool));
515 }
516
517 r->content_encoding = apr_table_get(r->headers_out, "Content-Encoding");
518 //r->content_type = apr_table_get(r->headers_out, "Content-Type"); -- already set above
519
520 const char *lng = apr_table_get(r->headers_out, "Content-Languages");
521
522 if(lng != NULL)
523 {
524 r->content_languages = apr_array_make(r->pool, 1, sizeof(const char *));
525
526 *(const char **)apr_array_push(r->content_languages) = lng;
527 }
528
529 // Disable kernel caching for this response
530 // Probably we don't have to do it for ModSecurity
531
532 //pHttpContext->GetResponse()->DisableKernelCache(
533 // IISCacheEvents::HTTPSYS_CACHEABLE::HANDLER_HTTPSYS_UNFRIENDLY);
534
535 for(c = 0; c < pRawHttpResponse->EntityChunkCount; c++ )
536 {
537 pSourceDataChunk = &pRawHttpResponse->pEntityChunks[ c ];
538
539 switch( pSourceDataChunk->DataChunkType )
540 {
541 case HttpDataChunkFromMemory:
542 ulTotalLength += pSourceDataChunk->FromMemory.BufferLength;
543 break;
544 case HttpDataChunkFromFileHandle:
545 pFileByteRange = &pSourceDataChunk->FromFileHandle.ByteRange;
546 //
547 // File chunks may contain by ranges with unspecified length
548 // (HTTP_BYTE_RANGE_TO_EOF). In order to send parts of such a chunk,
549 // its necessary to know when the chunk is finished, and
550 // we need to move to the next chunk.
551 //
552 if ( pFileByteRange->Length.QuadPart == HTTP_BYTE_RANGE_TO_EOF)
553 {
554 if ( GetFileType( pSourceDataChunk->FromFileHandle.FileHandle ) ==
555 FILE_TYPE_DISK )
556 {
557 if ( !GetFileSizeEx( pSourceDataChunk->FromFileHandle.FileHandle,
558 &lFileSize ) )
559 {
560 DWORD dwError = GetLastError();
561 hr = HRESULT_FROM_WIN32(dwError);
562 goto Finished;
563 }
564
565 // put the resolved file length in the chunk, replacing
566 // HTTP_BYTE_RANGE_TO_EOF
567 pFileByteRange->Length.QuadPart =
568 lFileSize.QuadPart - pFileByteRange->StartingOffset.QuadPart;
569 }
570 else
571 {
572 hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
573 goto Finished;
574 }
575 }
576
577 ulTotalLength += pFileByteRange->Length.QuadPart;
578 break;
579 default:
580 // TBD: consider implementing HttpDataChunkFromFragmentCache,
581 // and HttpDataChunkFromFragmentCacheEx
582 hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
583 goto Finished;
584 }
585 }
586
587 rsc->m_pResponseBuffer = (char *)apr_palloc(rsc->m_pRequestRec->pool, ulTotalLength);
588
589 ulTotalLength = 0;
590
591 for(c = 0; c < pRawHttpResponse->EntityChunkCount; c++ )
592 {
593 pSourceDataChunk = &pRawHttpResponse->pEntityChunks[ c ];
594
595 switch( pSourceDataChunk->DataChunkType )
596 {
597 case HttpDataChunkFromMemory:
598 memcpy(rsc->m_pResponseBuffer + ulTotalLength, pSourceDataChunk->FromMemory.pBuffer, pSourceDataChunk->FromMemory.BufferLength);
599 ulTotalLength += pSourceDataChunk->FromMemory.BufferLength;
600 break;
601 case HttpDataChunkFromFileHandle:
602 pFileByteRange = &pSourceDataChunk->FromFileHandle.ByteRange;
603
604 if(ReadFileChunk(pSourceDataChunk, rsc->m_pResponseBuffer + ulTotalLength) != S_OK)
605 {
606 DWORD dwErr = GetLastError();
607
608 hr = HRESULT_FROM_WIN32(dwErr);
609 goto Finished;
610 }
611
612 ulTotalLength += pFileByteRange->Length.QuadPart;
613 break;
614 default:
615 // TBD: consider implementing HttpDataChunkFromFragmentCache,
616 // and HttpDataChunkFromFragmentCacheEx
617 hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
618 goto Finished;
619 }
620 }
621
622 rsc->m_pResponseLength = ulTotalLength;
623
624 //
625 // If there's no content-length set, we need to set it to avoid chunked transfer mode
626 // We can only do it if there is it's the only response to be sent.
627 //
628
629 DWORD dwFlags = pResponseProvider->GetFlags();
630
631 if (pResponseProvider->GetHeadersBeingSent() &&
632 (dwFlags & HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0 &&
633 pHttpContext->GetResponse()->GetHeader(HttpHeaderContentLength) == NULL)
634 {
635 CHAR szLength[21]; //Max length for a 64 bit int is 20
636
637 ZeroMemory(szLength, sizeof(szLength));
638
639 hr = StringCchPrintfA(
640 szLength,
641 sizeof(szLength) / sizeof(CHAR) - 1, "%d",
642 ulTotalLength);
643
644 if(FAILED(hr))
645 {
646 goto Finished;
647 }
648
649 hr = pHttpContext->GetResponse()->SetHeader(
650 HttpHeaderContentLength,
651 szLength,
652 (USHORT)strlen(szLength),
653 TRUE);
654
655 if(FAILED(hr))
656 {
657 goto Finished;
658 }
659 }
660
661 Finished:
662
663 int status = modsecProcessResponse(rsc->m_pRequestRec);
664
665 // the logic here is temporary, needs clarification
666 //
667 if(status != 0 && status != -1)
668 {
669 pHttpContext->GetResponse()->Clear();
670 pHttpContext->GetResponse()->SetStatus(status, "ModSecurity Action");
671 pHttpContext->SetRequestHandled();
672
673 rsc->FinishRequest();
674
675 LeaveCriticalSection(&m_csLock);
676
677 return RQ_NOTIFICATION_FINISH_REQUEST;
678 }
679 Exit:
680 // temporary hack, in reality OnSendRequest theoretically could possibly come before OnEndRequest
681 //
682 if(rsc != NULL)
683 rsc->FinishRequest();
684
685 LeaveCriticalSection(&m_csLock);
686
687 return RQ_NOTIFICATION_CONTINUE;
688 }
689
690 REQUEST_NOTIFICATION_STATUS
OnPostEndRequest(IN IHttpContext * pHttpContext,IN IHttpEventProvider * pProvider)691 CMyHttpModule::OnPostEndRequest(
692 IN IHttpContext * pHttpContext,
693 IN IHttpEventProvider * pProvider
694 )
695 {
696 REQUEST_STORED_CONTEXT *rsc = NULL;
697
698 rsc = (REQUEST_STORED_CONTEXT *)pHttpContext->GetModuleContextContainer()->GetModuleContext(g_pModuleContext);
699
700 // only finish request if OnSendResponse have been called already
701 //
702 if(rsc != NULL && rsc->m_pResponseBuffer != NULL)
703 {
704 EnterCriticalSection(&m_csLock);
705
706 rsc->FinishRequest();
707
708 LeaveCriticalSection(&m_csLock);
709 }
710
711 return RQ_NOTIFICATION_CONTINUE;
712 }
713
714 REQUEST_NOTIFICATION_STATUS
OnBeginRequest(IN IHttpContext * pHttpContext,IN IHttpEventProvider * pProvider)715 CMyHttpModule::OnBeginRequest(
716 IN IHttpContext * pHttpContext,
717 IN IHttpEventProvider * pProvider
718 )
719 {
720 HRESULT hr = S_OK;
721 IHttpRequest* pRequest = NULL;
722 MODSECURITY_STORED_CONTEXT* pConfig = NULL;
723
724 UNREFERENCED_PARAMETER ( pProvider );
725
726 EnterCriticalSection(&m_csLock);
727
728 if ( pHttpContext == NULL )
729 {
730 hr = E_UNEXPECTED;
731 goto Finished;
732 }
733
734 pRequest = pHttpContext->GetRequest();
735
736 if ( pRequest == NULL )
737 {
738 hr = E_UNEXPECTED;
739 goto Finished;
740 }
741
742 hr = MODSECURITY_STORED_CONTEXT::GetConfig(pHttpContext, &pConfig );
743
744 if ( FAILED( hr ) )
745 {
746 //hr = E_UNEXPECTED;
747 hr = S_OK;
748 goto Finished;
749 }
750
751 // If module is disabled, dont go any further
752 //
753 if( pConfig->GetIsEnabled() == false )
754 {
755 goto Finished;
756 }
757
758 if(pConfig->m_Config == NULL)
759 {
760 char *path;
761 USHORT pathlen;
762
763 hr = pConfig->GlobalWideCharToMultiByte(pConfig->GetPath(), wcslen(pConfig->GetPath()), &path, &pathlen);
764
765 if ( FAILED( hr ) )
766 {
767 hr = E_UNEXPECTED;
768 goto Finished;
769 }
770
771 pConfig->m_Config = modsecGetDefaultConfig();
772
773 PCWSTR servpath = pHttpContext->GetApplication()->GetApplicationPhysicalPath();
774 char *apppath;
775 USHORT apppathlen;
776
777 hr = pConfig->GlobalWideCharToMultiByte((WCHAR *)servpath, wcslen(servpath), &apppath, &apppathlen);
778
779 if ( FAILED( hr ) )
780 {
781 delete path;
782 hr = E_UNEXPECTED;
783 goto Finished;
784 }
785
786 if(path[0] != 0)
787 {
788 const char * err = modsecProcessConfig((directory_config *)pConfig->m_Config, path, apppath);
789
790 if(err != NULL)
791 {
792 WriteEventViewerLog(err, EVENTLOG_ERROR_TYPE);
793 delete apppath;
794 delete path;
795 goto Finished;
796 }
797
798 modsecReportRemoteLoadedRules();
799 if (this->status_call_already_sent == false)
800 {
801 this->status_call_already_sent = true;
802 modsecStatusEngineCall();
803 }
804 }
805
806 delete apppath;
807 delete path;
808 }
809
810 conn_rec *c;
811 request_rec *r;
812
813 c = modsecNewConnection();
814
815 modsecProcessConnection(c);
816
817 r = modsecNewRequest(c, (directory_config *)pConfig->m_Config);
818
819 // on IIS we force input stream inspection flag, because its absence does not add any performance gain
820 // it's because on IIS request body must be restored each time it was read
821 //
822 modsecSetConfigForIISRequestBody(r);
823
824 REQUEST_STORED_CONTEXT *rsc = new REQUEST_STORED_CONTEXT();
825
826 rsc->m_pConnRec = c;
827 rsc->m_pRequestRec = r;
828 rsc->m_pHttpContext = pHttpContext;
829 rsc->m_pProvider = pProvider;
830
831 pHttpContext->GetModuleContextContainer()->SetModuleContext(rsc, g_pModuleContext);
832
833 StoreIISContext(r, rsc);
834
835 HTTP_REQUEST *req = pRequest->GetRawHttpRequest();
836
837 r->hostname = ConvertUTF16ToUTF8(req->CookedUrl.pHost, req->CookedUrl.HostLength / sizeof(WCHAR), r->pool);
838 r->path_info = ConvertUTF16ToUTF8(req->CookedUrl.pAbsPath, req->CookedUrl.AbsPathLength / sizeof(WCHAR), r->pool);
839
840 if(r->hostname == NULL)
841 {
842 if(req->Headers.KnownHeaders[HttpHeaderHost].pRawValue != NULL)
843 r->hostname = ZeroTerminate(req->Headers.KnownHeaders[HttpHeaderHost].pRawValue,
844 req->Headers.KnownHeaders[HttpHeaderHost].RawValueLength, r->pool);
845 }
846
847 int port = 0;
848 char *port_str = NULL;
849
850 if(r->hostname != NULL)
851 {
852 int k = 0;
853 char *ptr = (char *)r->hostname;
854
855 while(*ptr != 0 && *ptr != ':')
856 ptr++;
857
858 if(*ptr == ':')
859 {
860 *ptr = 0;
861 port_str = ptr + 1;
862 port = atoi(port_str);
863 }
864 }
865
866 if(req->CookedUrl.pQueryString != NULL && req->CookedUrl.QueryStringLength > 0)
867 r->args = ConvertUTF16ToUTF8(req->CookedUrl.pQueryString + 1, (req->CookedUrl.QueryStringLength / sizeof(WCHAR)) - 1, r->pool);
868
869 #define _TRANSHEADER(id,str) if(req->Headers.KnownHeaders[id].pRawValue != NULL) \
870 {\
871 apr_table_setn(r->headers_in, str, \
872 ZeroTerminate(req->Headers.KnownHeaders[id].pRawValue, req->Headers.KnownHeaders[id].RawValueLength, r->pool)); \
873 }
874
875 _TRANSHEADER(HttpHeaderCacheControl, "Cache-Control");
876 _TRANSHEADER(HttpHeaderConnection, "Connection");
877 _TRANSHEADER(HttpHeaderDate, "Date");
878 _TRANSHEADER(HttpHeaderKeepAlive, "Keep-Alive");
879 _TRANSHEADER(HttpHeaderPragma, "Pragma");
880 _TRANSHEADER(HttpHeaderTrailer, "Trailer");
881 _TRANSHEADER(HttpHeaderTransferEncoding, "Transfer-Encoding");
882 _TRANSHEADER(HttpHeaderUpgrade, "Upgrade");
883 _TRANSHEADER(HttpHeaderVia, "Via");
884 _TRANSHEADER(HttpHeaderWarning, "Warning");
885 _TRANSHEADER(HttpHeaderAllow, "Allow");
886 _TRANSHEADER(HttpHeaderContentLength, "Content-Length");
887 _TRANSHEADER(HttpHeaderContentType, "Content-Type");
888 _TRANSHEADER(HttpHeaderContentEncoding, "Content-Encoding");
889 _TRANSHEADER(HttpHeaderContentLanguage, "Content-Language");
890 _TRANSHEADER(HttpHeaderContentLocation, "Content-Location");
891 _TRANSHEADER(HttpHeaderContentMd5, "Content-Md5");
892 _TRANSHEADER(HttpHeaderContentRange, "Content-Range");
893 _TRANSHEADER(HttpHeaderExpires, "Expires");
894 _TRANSHEADER(HttpHeaderLastModified, "Last-Modified");
895 _TRANSHEADER(HttpHeaderAccept, "Accept");
896 _TRANSHEADER(HttpHeaderAcceptCharset, "Accept-Charset");
897 _TRANSHEADER(HttpHeaderAcceptEncoding, "Accept-Encoding");
898 _TRANSHEADER(HttpHeaderAcceptLanguage, "Accept-Language");
899 _TRANSHEADER(HttpHeaderAuthorization, "Authorization");
900 _TRANSHEADER(HttpHeaderCookie, "Cookie");
901 _TRANSHEADER(HttpHeaderExpect, "Expect");
902 _TRANSHEADER(HttpHeaderFrom, "From");
903 _TRANSHEADER(HttpHeaderHost, "Host");
904 _TRANSHEADER(HttpHeaderIfMatch, "If-Match");
905 _TRANSHEADER(HttpHeaderIfModifiedSince, "If-Modified-Since");
906 _TRANSHEADER(HttpHeaderIfNoneMatch, "If-None-Match");
907 _TRANSHEADER(HttpHeaderIfRange, "If-Range");
908 _TRANSHEADER(HttpHeaderIfUnmodifiedSince, "If-Unmodified-Since");
909 _TRANSHEADER(HttpHeaderMaxForwards, "Max-Forwards");
910 _TRANSHEADER(HttpHeaderProxyAuthorization, "Proxy-Authorization");
911 _TRANSHEADER(HttpHeaderReferer, "Referer");
912 _TRANSHEADER(HttpHeaderRange, "Range");
913 _TRANSHEADER(HttpHeaderTe, "TE");
914 _TRANSHEADER(HttpHeaderTranslate, "Translate");
915 _TRANSHEADER(HttpHeaderUserAgent, "User-Agent");
916
917 #undef _TRANSHEADER
918
919 for(int i = 0; i < req->Headers.UnknownHeaderCount; i++)
920 {
921 apr_table_setn(r->headers_in,
922 ZeroTerminate(req->Headers.pUnknownHeaders[i].pName, req->Headers.pUnknownHeaders[i].NameLength, r->pool),
923 ZeroTerminate(req->Headers.pUnknownHeaders[i].pRawValue, req->Headers.pUnknownHeaders[i].RawValueLength, r->pool));
924 }
925
926 r->content_encoding = apr_table_get(r->headers_in, "Content-Encoding");
927 r->content_type = apr_table_get(r->headers_in, "Content-Type");
928
929 const char *lng = apr_table_get(r->headers_in, "Content-Languages");
930
931 if(lng != NULL)
932 {
933 r->content_languages = apr_array_make(r->pool, 1, sizeof(const char *));
934
935 *(const char **)apr_array_push(r->content_languages) = lng;
936 }
937
938 switch(req->Verb)
939 {
940 case HttpVerbUnparsed:
941 case HttpVerbUnknown:
942 case HttpVerbInvalid:
943 case HttpVerbTRACK: // used by Microsoft Cluster Server for a non-logged trace
944 case HttpVerbSEARCH:
945 default:
946 r->method = "INVALID";
947 r->method_number = M_INVALID;
948 break;
949 case HttpVerbOPTIONS:
950 r->method = "OPTIONS";
951 r->method_number = M_OPTIONS;
952 break;
953 case HttpVerbGET:
954 case HttpVerbHEAD:
955 r->method = "GET";
956 r->method_number = M_GET;
957 break;
958 case HttpVerbPOST:
959 r->method = "POST";
960 r->method_number = M_POST;
961 break;
962 case HttpVerbPUT:
963 r->method = "PUT";
964 r->method_number = M_PUT;
965 break;
966 case HttpVerbDELETE:
967 r->method = "DELETE";
968 r->method_number = M_DELETE;
969 break;
970 case HttpVerbTRACE:
971 r->method = "TRACE";
972 r->method_number = M_TRACE;
973 break;
974 case HttpVerbCONNECT:
975 r->method = "CONNECT";
976 r->method_number = M_CONNECT;
977 break;
978 case HttpVerbMOVE:
979 r->method = "MOVE";
980 r->method_number = M_MOVE;
981 break;
982 case HttpVerbCOPY:
983 r->method = "COPY";
984 r->method_number = M_COPY;
985 break;
986 case HttpVerbPROPFIND:
987 r->method = "PROPFIND";
988 r->method_number = M_PROPFIND;
989 break;
990 case HttpVerbPROPPATCH:
991 r->method = "PROPPATCH";
992 r->method_number = M_PROPPATCH;
993 break;
994 case HttpVerbMKCOL:
995 r->method = "MKCOL";
996 r->method_number = M_MKCOL;
997 break;
998 case HttpVerbLOCK:
999 r->method = "LOCK";
1000 r->method_number = M_LOCK;
1001 break;
1002 case HttpVerbUNLOCK:
1003 r->method = "UNLOCK";
1004 r->method_number = M_UNLOCK;
1005 break;
1006 }
1007
1008 if(HTTP_EQUAL_VERSION(req->Version, 0, 9))
1009 r->protocol = "HTTP/0.9";
1010 else if(HTTP_EQUAL_VERSION(req->Version, 1, 0))
1011 r->protocol = "HTTP/1.0";
1012 else
1013 r->protocol = "HTTP/1.1";
1014
1015 r->request_time = apr_time_now();
1016
1017 r->parsed_uri.scheme = "http";
1018 r->parsed_uri.path = r->path_info;
1019 r->parsed_uri.hostname = (char *)r->hostname;
1020 r->parsed_uri.is_initialized = 1;
1021 r->parsed_uri.port = port;
1022 r->parsed_uri.port_str = port_str;
1023 r->parsed_uri.query = r->args;
1024 r->parsed_uri.dns_looked_up = 0;
1025 r->parsed_uri.dns_resolved = 0;
1026 r->parsed_uri.password = NULL;
1027 r->parsed_uri.user = NULL;
1028 r->parsed_uri.fragment = NULL;
1029
1030 r->unparsed_uri = ZeroTerminate(req->pRawUrl, req->RawUrlLength, r->pool);
1031 r->uri = r->unparsed_uri;
1032
1033 r->the_request = (char *)apr_palloc(r->pool, strlen(r->method) + 1 + req->RawUrlLength + 1 + strlen(r->protocol) + 1);
1034
1035 strcpy(r->the_request, r->method);
1036 strcat(r->the_request, " ");
1037 strcat(r->the_request, r->uri);
1038 strcat(r->the_request, " ");
1039 strcat(r->the_request, r->protocol);
1040
1041 HTTP_REQUEST_ID httpRequestID;
1042 char *pszValue = (char *)apr_palloc(r->pool, 24);
1043
1044 httpRequestID = pRequest->GetRawHttpRequest()->RequestId;
1045
1046 _ui64toa(httpRequestID, pszValue, 10);
1047
1048 apr_table_setn(r->subprocess_env, "UNIQUE_ID", pszValue);
1049
1050 PSOCKADDR pAddr = pRequest->GetRemoteAddress();
1051
1052 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER < 3
1053 c->remote_addr = CopySockAddr(r->pool, pAddr);
1054 c->remote_ip = GetIpAddr(r->pool, pAddr);
1055 #else
1056 c->client_addr = CopySockAddr(r->pool, pAddr);
1057 c->client_ip = GetIpAddr(r->pool, pAddr);
1058 #endif
1059 c->remote_host = NULL;
1060
1061 LeaveCriticalSection(&m_csLock);
1062 int status = modsecProcessRequest(r);
1063 EnterCriticalSection(&m_csLock);
1064
1065 if(status != DECLINED)
1066 {
1067 pHttpContext->GetResponse()->SetStatus(status, "ModSecurity Action");
1068 pHttpContext->SetRequestHandled();
1069
1070 hr = E_FAIL;
1071 goto Finished;
1072 }
1073
1074 Finished:
1075 LeaveCriticalSection(&m_csLock);
1076
1077 if ( FAILED( hr ) )
1078 {
1079 return RQ_NOTIFICATION_FINISH_REQUEST;
1080 }
1081 return RQ_NOTIFICATION_CONTINUE;
1082 }
1083
1084
ReadBodyCallback(request_rec * r,char * buf,unsigned int length,unsigned int * readcnt,int * is_eos)1085 apr_status_t ReadBodyCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
1086 {
1087 REQUEST_STORED_CONTEXT *rsc = RetrieveIISContext(r);
1088
1089 *readcnt = 0;
1090
1091 if (rsc == NULL)
1092 {
1093 *is_eos = 1;
1094 return APR_SUCCESS;
1095 }
1096
1097 IHttpContext *pHttpContext = rsc->m_pHttpContext;
1098 IHttpRequest *pRequest = pHttpContext->GetRequest();
1099
1100 if (pRequest->GetRemainingEntityBytes() == 0)
1101 {
1102 *is_eos = 1;
1103 return APR_SUCCESS;
1104 }
1105
1106 HRESULT hr = pRequest->ReadEntityBody(buf, length, false, (DWORD *)readcnt, NULL);
1107
1108 if (FAILED(hr))
1109 {
1110 // End of data is okay.
1111 if (ERROR_HANDLE_EOF != (hr & 0x0000FFFF))
1112 {
1113 // Set the error status.
1114 rsc->m_pProvider->SetErrorStatus(hr);
1115 }
1116
1117 *is_eos = 1;
1118 }
1119
1120 return APR_SUCCESS;
1121 }
1122
WriteBodyCallback(request_rec * r,char * buf,unsigned int length)1123 apr_status_t WriteBodyCallback(request_rec *r, char *buf, unsigned int length)
1124 {
1125 REQUEST_STORED_CONTEXT *rsc = RetrieveIISContext(r);
1126
1127 if(rsc == NULL || rsc->m_pRequestRec == NULL)
1128 return APR_SUCCESS;
1129
1130 IHttpContext *pHttpContext = rsc->m_pHttpContext;
1131 IHttpRequest *pHttpRequest = pHttpContext->GetRequest();
1132
1133 CHAR szLength[21]; //Max length for a 64 bit int is 20
1134
1135 ZeroMemory(szLength, sizeof(szLength));
1136
1137 HRESULT hr = StringCchPrintfA(
1138 szLength,
1139 sizeof(szLength) / sizeof(CHAR) - 1, "%d",
1140 length);
1141
1142 if(FAILED(hr))
1143 {
1144 // not possible
1145 }
1146
1147 hr = pHttpRequest->SetHeader(
1148 HttpHeaderContentLength,
1149 szLength,
1150 (USHORT)strlen(szLength),
1151 TRUE);
1152
1153 if(FAILED(hr))
1154 {
1155 // possible, but there's nothing we can do
1156 }
1157
1158 // since we clean the APR pool at the end of OnSendRequest, we must get IIS-managed memory chunk
1159 //
1160 void *reqbuf = pHttpContext->AllocateRequestMemory(length);
1161
1162 memcpy(reqbuf, buf, length);
1163
1164 pHttpRequest->InsertEntityBody(reqbuf, length);
1165
1166 return APR_SUCCESS;
1167 }
1168
ReadResponseCallback(request_rec * r,char * buf,unsigned int length,unsigned int * readcnt,int * is_eos)1169 apr_status_t ReadResponseCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
1170 {
1171 REQUEST_STORED_CONTEXT *rsc = RetrieveIISContext(r);
1172
1173 *readcnt = 0;
1174
1175 if(rsc == NULL || rsc->m_pResponseBuffer == NULL)
1176 {
1177 *is_eos = 1;
1178 return APR_SUCCESS;
1179 }
1180
1181 unsigned int size = length;
1182
1183 if(size > rsc->m_pResponseLength - rsc->m_pResponsePosition)
1184 size = rsc->m_pResponseLength - rsc->m_pResponsePosition;
1185
1186 memcpy(buf, rsc->m_pResponseBuffer + rsc->m_pResponsePosition, size);
1187
1188 *readcnt = size;
1189 rsc->m_pResponsePosition += size;
1190
1191 if(rsc->m_pResponsePosition >= rsc->m_pResponseLength)
1192 *is_eos = 1;
1193
1194 return APR_SUCCESS;
1195 }
1196
WriteResponseCallback(request_rec * r,char * buf,unsigned int length)1197 apr_status_t WriteResponseCallback(request_rec *r, char *buf, unsigned int length)
1198 {
1199 REQUEST_STORED_CONTEXT *rsc = RetrieveIISContext(r);
1200
1201 if(rsc == NULL || rsc->m_pRequestRec == NULL || rsc->m_pResponseBuffer == NULL)
1202 return APR_SUCCESS;
1203
1204 IHttpContext *pHttpContext = rsc->m_pHttpContext;
1205 IHttpResponse *pHttpResponse = pHttpContext->GetResponse();
1206 HTTP_RESPONSE *pRawHttpResponse = pHttpResponse->GetRawHttpResponse();
1207 HTTP_DATA_CHUNK *pDataChunk = (HTTP_DATA_CHUNK *)apr_palloc(rsc->m_pRequestRec->pool, sizeof(HTTP_DATA_CHUNK));
1208
1209 pRawHttpResponse->EntityChunkCount = 0;
1210
1211 // since we clean the APR pool at the end of OnSendRequest, we must get IIS-managed memory chunk
1212 //
1213 void *reqbuf = pHttpContext->AllocateRequestMemory(length);
1214
1215 memcpy(reqbuf, buf, length);
1216
1217 pDataChunk->DataChunkType = HttpDataChunkFromMemory;
1218 pDataChunk->FromMemory.pBuffer = reqbuf;
1219 pDataChunk->FromMemory.BufferLength = length;
1220
1221 CHAR szLength[21]; //Max length for a 64 bit int is 20
1222
1223 ZeroMemory(szLength, sizeof(szLength));
1224
1225 HRESULT hr = StringCchPrintfA(
1226 szLength,
1227 sizeof(szLength) / sizeof(CHAR) - 1, "%d",
1228 length);
1229
1230 if(FAILED(hr))
1231 {
1232 // not possible
1233 }
1234
1235 hr = pHttpResponse->SetHeader(
1236 HttpHeaderContentLength,
1237 szLength,
1238 (USHORT)strlen(szLength),
1239 TRUE);
1240
1241 if(FAILED(hr))
1242 {
1243 // possible, but there's nothing we can do
1244 }
1245
1246 pHttpResponse->WriteEntityChunkByReference(pDataChunk);
1247
1248 return APR_SUCCESS;
1249 }
1250
1251
CMyHttpModule()1252 CMyHttpModule::CMyHttpModule()
1253 {
1254 // Open a handle to the Event Viewer.
1255 m_hEventLog = RegisterEventSource( NULL, "ModSecurity" );
1256
1257 SYSTEM_INFO sysInfo;
1258
1259 GetSystemInfo(&sysInfo);
1260 m_dwPageSize = sysInfo.dwPageSize;
1261
1262 this->status_call_already_sent = false;
1263
1264 InitializeCriticalSection(&m_csLock);
1265
1266 modsecSetLogHook(this, Log);
1267
1268 modsecSetReadBody(ReadBodyCallback);
1269 modsecSetReadResponse(ReadResponseCallback);
1270 modsecSetWriteBody(WriteBodyCallback);
1271 modsecSetWriteResponse(WriteResponseCallback);
1272
1273 server_rec *s = modsecInit();
1274 char *compname = (char *)malloc(128);
1275 DWORD size = 128;
1276
1277 GetComputerName(compname, &size);
1278
1279 s->server_hostname = compname;
1280
1281 modsecStartConfig();
1282
1283 modsecFinalizeConfig();
1284
1285 modsecInitProcess();
1286 }
1287
~CMyHttpModule()1288 CMyHttpModule::~CMyHttpModule()
1289 {
1290 // ModSecurity registers APR pool cleanups, which interfere with APR pool tear down process
1291 // this causes crashes and since we are exiting the process here, so this is a temporary solution
1292 //
1293 //modsecTerminate();
1294
1295 //WriteEventViewerLog("Module deleted.");
1296
1297 // Test whether the handle for the Event Viewer is open.
1298 if (NULL != m_hEventLog)
1299 {
1300 // Close the handle to the Event Viewer.
1301 DeregisterEventSource( m_hEventLog );
1302 m_hEventLog = NULL;
1303
1304 DeleteCriticalSection(&m_csLock);
1305 }
1306 }
1307
Dispose()1308 void CMyHttpModule::Dispose()
1309 {
1310 }
1311
WriteEventViewerLog(LPCSTR szNotification,WORD category)1312 BOOL CMyHttpModule::WriteEventViewerLog(LPCSTR szNotification, WORD category)
1313 {
1314 // Test whether the handle for the Event Viewer is open.
1315 if (NULL != m_hEventLog)
1316 {
1317 // Write any strings to the Event Viewer and return.
1318 return ReportEvent(
1319 m_hEventLog,
1320 category, 0, 0x1,
1321 NULL, 1, 0, &szNotification, NULL );
1322 }
1323 return FALSE;
1324 }
1325