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