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 "httpserv.h"
22
23 // Project header files
24 #include "mymodule.h"
25 #include "mymodulefactory.h"
26 #include "moduleconfig.h"
27
28 HRESULT
Initialize(IHttpContext * pW3Context,IAppHostConfigException ** ppException)29 MODSECURITY_STORED_CONTEXT::Initialize(
30 IHttpContext * pW3Context,
31 IAppHostConfigException ** ppException
32 )
33 {
34 HRESULT hr = S_OK;
35 IAppHostAdminManager *pAdminManager = NULL;
36 IAppHostElement *pSessionTrackingElement = NULL;
37 IAppHostPropertyException *pPropertyException = NULL;
38
39 PCWSTR pszConfigPath = pW3Context->GetMetadata()->GetMetaPath();
40 BSTR bstrUrlPath = SysAllocString( pszConfigPath );
41
42 pAdminManager = g_pHttpServer->GetAdminManager();
43
44 if ( ( FAILED( hr ) ) || ( pAdminManager == NULL ) )
45 {
46 hr = E_UNEXPECTED;
47 goto Failure;
48 }
49
50 // Get a handle to the section:
51 hr = pAdminManager->GetAdminSection(
52 MODSECURITY_SECTION,
53 bstrUrlPath,
54 &pSessionTrackingElement );
55
56 if ( FAILED( hr ) )
57 {
58 goto Failure;
59 }
60
61 if ( pSessionTrackingElement == NULL )
62 {
63 hr = E_UNEXPECTED;
64 goto Failure;
65 }
66
67 // Get the property object for the 'enabled' attribute:
68 hr = GetBooleanPropertyValue(
69 pSessionTrackingElement,
70 MODSECURITY_SECTION_ENABLED,
71 &pPropertyException,
72 &m_bIsEnabled);
73
74 if ( FAILED( hr ) )
75 {
76 goto Failure;
77 }
78
79 // If there is a config failure, we cannot continue execution:
80 if ( pPropertyException != NULL )
81 {
82
83 ppException = ( IAppHostConfigException** ) &pPropertyException;
84 goto Failure;
85 }
86
87 if ( m_bIsEnabled == FALSE )
88 {
89 // There is no point in reading any more of the config associated with the session
90 // tracking section, since this feature is not enabled for the current URL
91 goto Failure;
92 }
93
94 // Get the property object for the 'configfile' attribute:
95 hr = GetStringPropertyValue(
96 pSessionTrackingElement,
97 MODSECURITY_SECTION_CONFIGFILE,
98 &pPropertyException,
99 &m_pszPath);
100
101 if ( FAILED( hr ) )
102 {
103 goto Failure;
104 }
105
106 // If there is a config failure, we cannot continue execution:
107 if ( pPropertyException != NULL )
108 {
109
110 ppException = ( IAppHostConfigException** ) &pPropertyException;
111 goto Failure;
112 }
113
114 Failure:
115 SysFreeString( bstrUrlPath );
116 return hr;
117 }
118
119 HRESULT
GetBooleanPropertyValue(IAppHostElement * pElement,WCHAR * pszPropertyName,IAppHostPropertyException ** pException,BOOL * pBoolValue)120 MODSECURITY_STORED_CONTEXT::GetBooleanPropertyValue(
121 IAppHostElement* pElement,
122 WCHAR* pszPropertyName,
123 IAppHostPropertyException** pException,
124 BOOL* pBoolValue )
125 {
126 HRESULT hr = S_OK;
127 IAppHostProperty *pProperty = NULL;
128 VARIANT vPropertyValue;
129
130 if (
131 ( pElement == NULL ) ||
132 ( pszPropertyName == NULL ) ||
133 ( pException == NULL ) ||
134 ( pBoolValue == NULL )
135 )
136 {
137 hr = E_INVALIDARG;
138 goto Failure;
139 }
140
141 // Get the property object for the BOOLEAN attribute:
142 hr = pElement->GetPropertyByName(
143 pszPropertyName,
144 &pProperty );
145
146 if ( FAILED( hr ) )
147 {
148 goto Failure;
149 }
150
151 if ( pProperty == NULL )
152 {
153 hr = E_UNEXPECTED;
154 goto Failure;
155 }
156
157 // Get the attribute value:
158 VariantInit( &vPropertyValue );
159
160 hr = pProperty->get_Value( &vPropertyValue );
161
162 if ( FAILED( hr ) )
163 {
164 goto Failure;
165 }
166
167 // See it there is an exception that might be due to the actual value in the
168 // config not meeting validation criteria
169 *pException = NULL;
170
171 hr = pProperty->get_Exception( pException );
172
173 if ( FAILED( hr ) )
174 {
175 goto Failure;
176 }
177
178 // No need to continue if we got an exception...
179 if ( ( *pException ) != NULL )
180 {
181 goto Failure;
182 }
183
184 // Finally, get the value:
185 *pBoolValue = ( vPropertyValue.boolVal == VARIANT_TRUE ) ? TRUE : FALSE;
186
187
188 Failure:
189 VariantClear( &vPropertyValue );
190
191 if ( pProperty != NULL )
192 {
193 pProperty->Release();
194 pProperty = NULL;
195 }
196
197 return hr;
198 }
199
200 HRESULT
GetDWORDPropertyValue(IAppHostElement * pElement,WCHAR * pszPropertyName,IAppHostPropertyException ** pException,DWORD * pnValue)201 MODSECURITY_STORED_CONTEXT::GetDWORDPropertyValue(
202 IAppHostElement* pElement,
203 WCHAR* pszPropertyName,
204 IAppHostPropertyException** pException,
205 DWORD* pnValue )
206 {
207 HRESULT hr = S_OK;
208 IAppHostProperty *pProperty = NULL;
209 VARIANT vPropertyValue;
210
211 if (
212 ( pElement == NULL ) ||
213 ( pszPropertyName == NULL ) ||
214 ( pException == NULL ) ||
215 ( pnValue == NULL )
216 )
217 {
218 hr = E_INVALIDARG;
219 goto Failure;
220 }
221
222 // Get the property object for the INT attribute:
223 hr = pElement->GetPropertyByName(
224 pszPropertyName,
225 &pProperty );
226
227 if ( FAILED( hr ) )
228 {
229 goto Failure;
230 }
231
232 if ( pProperty == NULL )
233 {
234 hr = E_UNEXPECTED;
235 goto Failure;
236 }
237
238 // Get the attribute value:
239 VariantInit( &vPropertyValue );
240
241 hr = pProperty->get_Value( &vPropertyValue );
242
243 if ( FAILED( hr ) )
244 {
245 goto Failure;
246 }
247
248 // See it there is an exception that might be due to the actual value in the
249 // config not meeting validation criteria
250 *pException = NULL;
251
252 hr = pProperty->get_Exception( pException );
253
254 if ( FAILED( hr ) )
255 {
256 goto Failure;
257 }
258
259 // No need to continue if we got an exception...
260 if ( ( *pException ) != NULL )
261 {
262 goto Failure;
263 }
264
265 // Finally, get the value:
266 *pnValue = vPropertyValue.ulVal;
267
268 Failure:
269 VariantClear( &vPropertyValue );
270
271 if ( pProperty != NULL )
272 {
273 pProperty->Release();
274 pProperty = NULL;
275 }
276
277 return hr;
278 }
279
280 HRESULT
GetTimeSpanPropertyValue(IAppHostElement * pElement,WCHAR * pszPropertyName,IAppHostPropertyException ** pException,ULONGLONG * pnValue)281 MODSECURITY_STORED_CONTEXT::GetTimeSpanPropertyValue(
282 IAppHostElement* pElement,
283 WCHAR* pszPropertyName,
284 IAppHostPropertyException** pException,
285 ULONGLONG* pnValue )
286 {
287 HRESULT hr = S_OK;
288 IAppHostProperty *pProperty = NULL;
289 VARIANT vPropertyValue;
290
291 if (
292 ( pElement == NULL ) ||
293 ( pszPropertyName == NULL ) ||
294 ( pException == NULL ) ||
295 ( pnValue == NULL )
296 )
297 {
298 hr = E_INVALIDARG;
299 goto Failure;
300 }
301
302 // Get the property object for the INT attribute:
303 hr = pElement->GetPropertyByName(
304 pszPropertyName,
305 &pProperty );
306
307 if ( FAILED( hr ) )
308 {
309 goto Failure;
310 }
311
312 if ( pProperty == NULL )
313 {
314 hr = E_UNEXPECTED;
315 goto Failure;
316 }
317
318 // Get the attribute value:
319 VariantInit( &vPropertyValue );
320
321 hr = pProperty->get_Value( &vPropertyValue );
322
323 if ( FAILED( hr ) )
324 {
325 goto Failure;
326 }
327
328 // See it there is an exception that might be due to the actual value in the
329 // config not meeting validation criteria
330 *pException = NULL;
331
332 hr = pProperty->get_Exception( pException );
333
334 if ( FAILED( hr ) )
335 {
336 goto Failure;
337 }
338
339 // No need to continue if we got an exception...
340 if ( ( *pException ) != NULL )
341 {
342 goto Failure;
343 }
344
345 // Finally, get the value:
346 *pnValue = vPropertyValue.ullVal;
347
348 Failure:
349 VariantClear( &vPropertyValue );
350
351 if ( pProperty != NULL )
352 {
353 pProperty->Release();
354 pProperty = NULL;
355 }
356
357 return hr;
358 }
359
360 HRESULT
GetStringPropertyValue(IAppHostElement * pElement,WCHAR * pszPropertyName,IAppHostPropertyException ** pException,WCHAR ** ppszValue)361 MODSECURITY_STORED_CONTEXT::GetStringPropertyValue(
362 IAppHostElement* pElement,
363 WCHAR* pszPropertyName,
364 IAppHostPropertyException** pException,
365 WCHAR** ppszValue )
366 {
367 HRESULT hr = S_OK;
368 IAppHostProperty *pProperty = NULL;
369 DWORD dwLength;
370 VARIANT vPropertyValue;
371
372 if (
373 ( pElement == NULL ) ||
374 ( pszPropertyName == NULL ) ||
375 ( pException == NULL ) ||
376 ( ppszValue == NULL )
377 )
378 {
379 hr = E_INVALIDARG;
380 goto Failure;
381 }
382
383 *ppszValue = NULL;
384
385 // Get the property object for the string attribute:
386 hr = pElement->GetPropertyByName(
387 pszPropertyName,
388 &pProperty );
389
390 if ( FAILED( hr ) )
391 {
392 goto Failure;
393 }
394
395 if ( pProperty == NULL )
396 {
397 hr = E_UNEXPECTED;
398 goto Failure;
399 }
400
401 // Get the attribute value:
402 VariantInit( &vPropertyValue );
403
404 hr = pProperty->get_Value( &vPropertyValue );
405
406 if ( FAILED( hr ) )
407 {
408 goto Failure;
409 }
410
411 // See it there is an exception that might be due to the actual value in the
412 // config not meeting validation criteria
413 *pException = NULL;
414
415 hr = pProperty->get_Exception( pException );
416
417 if ( FAILED( hr ) )
418 {
419 goto Failure;
420 }
421
422 // No need to continue if we got an exception...
423 if ( ( *pException ) != NULL )
424 {
425 goto Failure;
426 }
427
428 // Finally, get the value:
429 dwLength = SysStringLen( vPropertyValue.bstrVal );
430 *ppszValue = new WCHAR[ dwLength + 1 ];
431
432 if ( (*ppszValue) == NULL )
433 {
434 hr = E_OUTOFMEMORY;
435 goto Failure;
436 }
437
438 wcsncpy(
439 *ppszValue,
440 vPropertyValue.bstrVal,
441 dwLength );
442
443 (*ppszValue)[ dwLength ] = L'\0';
444
445 Failure:
446 VariantClear( &vPropertyValue );
447
448 if ( pProperty != NULL )
449 {
450 pProperty->Release();
451 pProperty = NULL;
452 }
453
454 return hr;
455 }
456
~MODSECURITY_STORED_CONTEXT()457 MODSECURITY_STORED_CONTEXT::~MODSECURITY_STORED_CONTEXT()
458 {
459 if ( m_pszPath != NULL )
460 {
461 delete [] m_pszPath;
462 m_pszPath = NULL;
463 }
464 }
465
MODSECURITY_STORED_CONTEXT()466 MODSECURITY_STORED_CONTEXT::MODSECURITY_STORED_CONTEXT():
467 m_bIsEnabled ( FALSE ),
468 m_pszPath( NULL ),
469 m_Config( NULL )
470 {
471 }
472
473 DWORD
GlobalWideCharToMultiByte(WCHAR * pSource,DWORD dwLengthSource,CHAR ** ppszDestination,USHORT * pdwLengthDestination)474 MODSECURITY_STORED_CONTEXT::GlobalWideCharToMultiByte(
475 WCHAR* pSource,
476 DWORD dwLengthSource,
477 CHAR** ppszDestination,
478 USHORT* pdwLengthDestination )
479 {
480 DWORD dwResult = NULL;
481 DWORD dwCount = 0;
482
483 if (
484 ( pSource == NULL ) ||
485 ( ppszDestination == NULL ) ||
486 ( pdwLengthDestination == NULL )
487 )
488 {
489 dwResult = ERROR_INVALID_PARAMETER;
490 goto Exit;
491 }
492
493 // Initialize result length
494 *pdwLengthDestination = 0;
495 *ppszDestination = NULL;
496
497 dwCount = WideCharToMultiByte(
498 CP_ACP,
499 0,
500 pSource,
501 dwLengthSource + 1,
502 *ppszDestination,
503 0,
504 NULL,
505 NULL );
506
507 if ( 0 == dwCount )
508 {
509 dwResult = GetLastError ();
510
511 if ( dwResult == 0 )
512 {
513 dwResult = ERROR_INVALID_DATA;
514 }
515
516 goto Exit;
517 }
518
519 *ppszDestination = new CHAR[ dwCount + 1 ];
520
521 if ( NULL == ( *ppszDestination ) )
522 {
523 dwResult = ERROR_OUTOFMEMORY;
524 goto Exit;
525 }
526
527 // Make sure the memory is 'clean':
528 SecureZeroMemory(
529 ( *ppszDestination ),
530 ( dwCount + 1 ) * sizeof ( CHAR ) );
531
532 if (
533 0 == WideCharToMultiByte(
534 CP_ACP,
535 0,
536 pSource,
537 dwLengthSource + 1,
538 *ppszDestination,
539 dwCount,
540 NULL,
541 NULL )
542 )
543 {
544 dwResult = GetLastError();
545
546 goto Exit;
547 }
548
549 *pdwLengthDestination = ( USHORT )dwCount;
550
551 Exit:
552 if ( dwResult != 0 )
553 {
554 // Make sure we do the proper cleanup in the error case:
555 if ( pdwLengthDestination != NULL )
556 {
557 *pdwLengthDestination = 0;
558 }
559
560 if ( ppszDestination != NULL )
561 {
562 if ( ( *ppszDestination ) != NULL )
563 {
564 delete [] ( *ppszDestination );
565 ( *ppszDestination ) = NULL;
566 }
567 }
568 }
569
570 return dwResult;
571 }
572
573 HRESULT
GetConfig(IHttpContext * pContext,MODSECURITY_STORED_CONTEXT ** ppModuleConfig)574 MODSECURITY_STORED_CONTEXT::GetConfig(
575 IHttpContext * pContext,
576 MODSECURITY_STORED_CONTEXT ** ppModuleConfig
577 )
578 {
579 HRESULT hr = S_OK;
580 MODSECURITY_STORED_CONTEXT * pModuleConfig = NULL;
581 IHttpModuleContextContainer * pMetadataContainer = NULL;
582 IAppHostConfigException * pException = NULL;
583
584 pMetadataContainer = pContext->GetMetadata()->GetModuleContextContainer();
585
586 if ( pMetadataContainer == NULL )
587 {
588 hr = E_UNEXPECTED;
589 return hr;
590 }
591
592 pModuleConfig = (MODSECURITY_STORED_CONTEXT *)pMetadataContainer->GetModuleContext( g_pModuleContext );
593 if ( pModuleConfig != NULL )
594 {
595 //
596 // We found stored data for this module for the metadata
597 // object which is different for unique configuration path
598 //
599 *ppModuleConfig = pModuleConfig;
600 return S_OK;
601 }
602
603 //
604 // If we reach here, that means this is first request or first
605 // request after a configuration change IIS core will throw stored context away
606 // if a change notification arrives for this metadata path
607 //
608 pModuleConfig = new MODSECURITY_STORED_CONTEXT();
609 if ( pModuleConfig == NULL )
610 {
611 return E_OUTOFMEMORY;
612 }
613
614 //
615 // Read module configuration data and store in MODSECURITY_STORED_CONTEXT
616 //
617 hr = pModuleConfig->Initialize( pContext, &pException );
618 if ( FAILED( hr ) || pException != NULL )
619 {
620 pModuleConfig->CleanupStoredContext();
621
622 pModuleConfig = NULL;
623 hr = E_UNEXPECTED;
624
625 return hr;
626 }
627
628 //
629 // Store MODSECURITY_STORED_CONTEXT data as metadata stored context
630 //
631 hr = pMetadataContainer->SetModuleContext( pModuleConfig,
632 g_pModuleContext );
633 if ( FAILED( hr ) )
634 {
635 pModuleConfig->CleanupStoredContext();
636 pModuleConfig = NULL;
637
638 //
639 // It is possible that some other thread stored context before this thread
640 // could do. Check returned hr and return context stored by other thread
641 //
642 if ( hr == HRESULT_FROM_WIN32( ERROR_ALREADY_ASSIGNED ) )
643 {
644 *ppModuleConfig = (MODSECURITY_STORED_CONTEXT *)pMetadataContainer->GetModuleContext( g_pModuleContext );
645 return S_OK;
646 }
647 }
648
649 *ppModuleConfig = pModuleConfig;
650 return hr;
651 }
652