/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % P r i n t K e y r i n g P r o p e r t i e s % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % PrintKeyringProperties() prints properties associated with each key in the % keyring. % % The format of the PrintKeyringProperties method is: % % WizardBooleanType PrintKeyringProperties(const char *path, % BlobInfo *keyring_blob,ExceptionInfo *exception) % % A description of each parameter follows: % % o path: the keyring path. % % o blob_ibfo: list the key properties to this blob. % % o exception: Return any errors or warnings in this structure. % */ WizardExport WizardBooleanType PrintKeyringProperties(const char *path, BlobInfo *keyring_blob,ExceptionInfo *exception) { char *canonical_path, *hex, *keyring_rdf, message[WizardPathExtent]; const struct stat *properties; FileInfo *file_info; KeyringInfo keyring_info; ssize_t count; StringInfo *filetype, *id, *key, *magick, *nonce, *target; size_t length; WizardSizeType timestamp; WizardStatusType status; (void) LogWizardEvent(TraceEvent,GetWizardModule(),"..."); WizardAssert(KeymapDomain,exception != (ExceptionInfo *) NULL); file_info=AcquireFileInfo(path,KeyringFilename,ReadFileMode,exception); if (file_info == (FileInfo *) NULL) return(WizardTrue); keyring_rdf=AcquireString(" <keyring:Keyring rdf:about=\""); canonical_path=CanonicalXMLContent(GetFilePath(file_info),WizardFalse); (void) ConcatenateString(&keyring_rdf,canonical_path); (void) ConcatenateString(&keyring_rdf,"\">\n"); properties=GetFileProperties(file_info); (void) ConcatenateString(&keyring_rdf," <keyring:modify-date>"); (void) FormatWizardTime(properties->st_mtime,WizardPathExtent,message); (void) ConcatenateString(&keyring_rdf,message); (void) ConcatenateString(&keyring_rdf,"</keyring:modify-date>\n"); (void) ConcatenateString(&keyring_rdf," <keyring:create-date>"); (void) FormatWizardTime(properties->st_mtime,WizardPathExtent,message); (void) ConcatenateString(&keyring_rdf,message); (void) ConcatenateString(&keyring_rdf,"</keyring:create-date>\n"); (void) ConcatenateString(&keyring_rdf," <keyring:timestamp>"); (void) FormatWizardTime(time((time_t *) NULL),WizardPathExtent,message); (void) ConcatenateString(&keyring_rdf,message); (void) ConcatenateString(&keyring_rdf,"</keyring:timestamp>\n"); (void) ConcatenateString(&keyring_rdf," </keyring:Keyring>\n"); length=strlen(keyring_rdf); count=WriteBlob(keyring_blob,length,(unsigned char *) keyring_rdf); keyring_rdf=DestroyString(keyring_rdf); if (count != (ssize_t) length) ThrowFileException(exception,FileError,GetFilePath(file_info)); magick=GetWizardMagick(WizardMagick,sizeof(WizardMagick)); target=CloneStringInfo(magick); status=ReadFileChunk(file_info,GetStringInfoDatum(target), GetStringInfoLength(target)); if ((status == WizardFalse) || (CompareStringInfo(target,magick) != 0)) { file_info=DestroyFileInfo(file_info,exception); (void) ThrowWizardException(exception,GetWizardModule(),KeyringError, "corrupt key ring file `%s'",GetFilePath(file_info)); return(WizardFalse); } magick=DestroyStringInfo(magick); target=DestroyStringInfo(target); filetype=GetWizardMagick((unsigned char *) KeyringFiletype, strlen(KeyringFiletype)); target=CloneStringInfo(filetype); status&=ReadFileChunk(file_info,GetStringInfoDatum(target), GetStringInfoLength(target)); if ((status == WizardFalse) || (CompareStringInfo(target,filetype) != 0)) { file_info=DestroyFileInfo(file_info,exception); (void) ThrowWizardException(exception,GetWizardModule(),KeyringError, "corrupt key ring file `%s'",GetFilePath(file_info)); return(WizardFalse); } filetype=DestroyStringInfo(filetype); target=DestroyStringInfo(target); length=0; (void) ResetWizardMemory(&keyring_info,0,sizeof(keyring_info)); while (ReadFile32Bits(file_info,&keyring_info.signature) != 0) { if (keyring_info.signature != WizardSignature) { file_info=DestroyFileInfo(file_info,exception); (void) ThrowWizardException(exception,GetWizardModule(),KeyringError, "corrupt key ring file `%s'",GetFilePath(file_info)); return(WizardFalse); } status&=ReadFile32Bits(file_info,&length); status&=ReadFile16Bits(file_info,&keyring_info.protocol_major); status&=ReadFile16Bits(file_info,&keyring_info.protocol_minor); if ((keyring_info.protocol_major == 1) && (keyring_info.protocol_minor == 0)) timestamp=(time_t) length; else status&=ReadFile64Bits(file_info,×tamp); keyring_info.timestamp=(time_t) timestamp; status&=ReadFile32Bits(file_info,&length); if (status == WizardFalse) { file_info=DestroyFileInfo(file_info,exception); (void) ThrowWizardException(exception,GetWizardModule(),KeyringError, "corrupt key ring file `%s'",GetFilePath(file_info)); return(WizardFalse); } id=AcquireStringInfo(length); status&=ReadFileChunk(file_info,GetStringInfoDatum(id), GetStringInfoLength(id)); status&=ReadFile32Bits(file_info,&length); if (status == WizardFalse) { file_info=DestroyFileInfo(file_info,exception); (void) ThrowWizardException(exception,GetWizardModule(),KeyringError, "corrupt key ring file `%s'",GetFilePath(file_info)); return(WizardFalse); } key=AcquireStringInfo(length); status&=ReadFileChunk(file_info,GetStringInfoDatum(key), GetStringInfoLength(key)); status&=ReadFile32Bits(file_info,&length); if (status == WizardFalse) { file_info=DestroyFileInfo(file_info,exception); (void) ThrowWizardException(exception,GetWizardModule(),KeyringError, "corrupt key ring file `%s'",GetFilePath(file_info)); return(WizardFalse); } nonce=AcquireStringInfo(length); status&=ReadFileChunk(file_info,GetStringInfoDatum(nonce), GetStringInfoLength(nonce)); keyring_rdf=AcquireString(" <keyring:Key rdf:about=\""); hex=StringInfoToHexString(id); (void) ConcatenateString(&keyring_rdf,hex); hex=DestroyString(hex); (void) ConcatenateString(&keyring_rdf,"\">\n"); (void) ConcatenateString(&keyring_rdf," <keyring:memberOf " "rdf:resource=\""); (void) ConcatenateString(&keyring_rdf,canonical_path); (void) ConcatenateString(&keyring_rdf,"\"/>\n"); (void) ConcatenateString(&keyring_rdf," <keyring:nonce>"); hex=StringInfoToHexString(nonce); (void) ConcatenateString(&keyring_rdf,hex); hex=DestroyString(hex); (void) ConcatenateString(&keyring_rdf,"</keyring:nonce>\n"); (void) ConcatenateString(&keyring_rdf," <keyring:timestamp>"); (void) FormatWizardTime(keyring_info.timestamp,WizardPathExtent,message); (void) ConcatenateString(&keyring_rdf,message); (void) ConcatenateString(&keyring_rdf,"</keyring:timestamp>\n"); (void) ConcatenateString(&keyring_rdf," <keyring:protocol>"); (void) FormatLocaleString(message,WizardPathExtent,"%u.%u", keyring_info.protocol_major,(unsigned int) keyring_info.protocol_minor); (void) ConcatenateString(&keyring_rdf,message); (void) ConcatenateString(&keyring_rdf,"</keyring:protocol>\n"); (void) ConcatenateString(&keyring_rdf," </keyring:Key>\n"); length=strlen(keyring_rdf); count=WriteBlob(keyring_blob,length,(unsigned char *) keyring_rdf); keyring_rdf=DestroyString(keyring_rdf); if (count != (ssize_t) length) ThrowFileException(exception,FileError,GetFilePath(file_info)); nonce=DestroyStringInfo(nonce); key=DestroyStringInfo(key); id=DestroyStringInfo(id); if (status == WizardFalse) { file_info=DestroyFileInfo(file_info,exception); (void) ThrowWizardException(exception,GetWizardModule(),KeyringError, "corrupt key ring file `%s'",GetFilePath(file_info)); return(WizardFalse); } } canonical_path=DestroyString(canonical_path); file_info=DestroyFileInfo(file_info,exception); return(WizardTrue); }
REQUEST_NOTIFICATION_STATUS CMyHttpModule::OnSendResponse( IN IHttpContext * pHttpContext, IN ISendResponseProvider * pResponseProvider ) { REQUEST_STORED_CONTEXT *rsc = NULL; rsc = (REQUEST_STORED_CONTEXT *)pHttpContext->GetModuleContextContainer()->GetModuleContext(g_pModuleContext); EnterCriticalSection(&m_csLock); // here we must check if response body processing is enabled // if(rsc == NULL || rsc->m_pRequestRec == NULL || rsc->m_pResponseBuffer != NULL || !modsecIsResponseBodyAccessEnabled(rsc->m_pRequestRec)) { goto Exit; } HRESULT hr = S_OK; IHttpResponse *pHttpResponse = NULL; HTTP_RESPONSE *pRawHttpResponse = NULL; HTTP_BYTE_RANGE *pFileByteRange = NULL; HTTP_DATA_CHUNK *pSourceDataChunk = NULL; LARGE_INTEGER lFileSize; REQUEST_NOTIFICATION_STATUS ret = RQ_NOTIFICATION_CONTINUE; ULONGLONG ulTotalLength = 0; DWORD c; request_rec *r = rsc->m_pRequestRec; pHttpResponse = pHttpContext->GetResponse(); pRawHttpResponse = pHttpResponse->GetRawHttpResponse(); // here we must add handling of chunked response // apparently IIS 7 calls this handler once per chunk // see: http://stackoverflow.com/questions/4385249/how-to-buffer-and-process-chunked-data-before-sending-headers-in-iis7-native-mod if(pRawHttpResponse->EntityChunkCount == 0) goto Exit; // here we must transfer response headers // USHORT ctcch = 0; char *ct = (char *)pHttpResponse->GetHeader(HttpHeaderContentType, &ctcch); char *ctz = ZeroTerminate(ct, ctcch, r->pool); // assume HTML if content type not set // without this output filter would not buffer response and processing would hang // if(ctz[0] == 0) ctz = "text/html"; r->content_type = ctz; #define _TRANSHEADER(id,str) if(pRawHttpResponse->Headers.KnownHeaders[id].pRawValue != NULL) \ {\ apr_table_setn(r->headers_out, str, \ ZeroTerminate(pRawHttpResponse->Headers.KnownHeaders[id].pRawValue, pRawHttpResponse->Headers.KnownHeaders[id].RawValueLength, r->pool)); \ } _TRANSHEADER(HttpHeaderCacheControl, "Cache-Control"); _TRANSHEADER(HttpHeaderConnection, "Connection"); _TRANSHEADER(HttpHeaderDate, "Date"); _TRANSHEADER(HttpHeaderKeepAlive, "Keep-Alive"); _TRANSHEADER(HttpHeaderPragma, "Pragma"); _TRANSHEADER(HttpHeaderTrailer, "Trailer"); _TRANSHEADER(HttpHeaderTransferEncoding, "Transfer-Encoding"); _TRANSHEADER(HttpHeaderUpgrade, "Upgrade"); _TRANSHEADER(HttpHeaderVia, "Via"); _TRANSHEADER(HttpHeaderWarning, "Warning"); _TRANSHEADER(HttpHeaderAllow, "Allow"); _TRANSHEADER(HttpHeaderContentLength, "Content-Length"); _TRANSHEADER(HttpHeaderContentType, "Content-Type"); _TRANSHEADER(HttpHeaderContentEncoding, "Content-Encoding"); _TRANSHEADER(HttpHeaderContentLanguage, "Content-Language"); _TRANSHEADER(HttpHeaderContentLocation, "Content-Location"); _TRANSHEADER(HttpHeaderContentMd5, "Content-Md5"); _TRANSHEADER(HttpHeaderContentRange, "Content-Range"); _TRANSHEADER(HttpHeaderExpires, "Expires"); _TRANSHEADER(HttpHeaderLastModified, "Last-Modified"); _TRANSHEADER(HttpHeaderAcceptRanges, "Accept-Ranges"); _TRANSHEADER(HttpHeaderAge, "Age"); _TRANSHEADER(HttpHeaderEtag, "Etag"); _TRANSHEADER(HttpHeaderLocation, "Location"); _TRANSHEADER(HttpHeaderProxyAuthenticate, "Proxy-Authenticate"); _TRANSHEADER(HttpHeaderRetryAfter, "Retry-After"); _TRANSHEADER(HttpHeaderServer, "Server"); _TRANSHEADER(HttpHeaderSetCookie, "Set-Cookie"); _TRANSHEADER(HttpHeaderVary, "Vary"); _TRANSHEADER(HttpHeaderWwwAuthenticate, "Www-Authenticate"); #undef _TRANSHEADER for(int i = 0; i < pRawHttpResponse->Headers.UnknownHeaderCount; i++) { apr_table_setn(r->headers_out, ZeroTerminate(pRawHttpResponse->Headers.pUnknownHeaders[i].pName, pRawHttpResponse->Headers.pUnknownHeaders[i].NameLength, r->pool), ZeroTerminate(pRawHttpResponse->Headers.pUnknownHeaders[i].pRawValue, pRawHttpResponse->Headers.pUnknownHeaders[i].RawValueLength, r->pool)); } r->content_encoding = apr_table_get(r->headers_out, "Content-Encoding"); //r->content_type = apr_table_get(r->headers_out, "Content-Type"); -- already set above const char *lng = apr_table_get(r->headers_out, "Content-Languages"); if(lng != NULL) { r->content_languages = apr_array_make(r->pool, 1, sizeof(const char *)); *(const char **)apr_array_push(r->content_languages) = lng; } // Disable kernel caching for this response // Probably we don't have to do it for ModSecurity //pHttpContext->GetResponse()->DisableKernelCache( // IISCacheEvents::HTTPSYS_CACHEABLE::HANDLER_HTTPSYS_UNFRIENDLY); for(c = 0; c < pRawHttpResponse->EntityChunkCount; c++ ) { pSourceDataChunk = &pRawHttpResponse->pEntityChunks[ c ]; switch( pSourceDataChunk->DataChunkType ) { case HttpDataChunkFromMemory: ulTotalLength += pSourceDataChunk->FromMemory.BufferLength; break; case HttpDataChunkFromFileHandle: pFileByteRange = &pSourceDataChunk->FromFileHandle.ByteRange; // // File chunks may contain by ranges with unspecified length // (HTTP_BYTE_RANGE_TO_EOF). In order to send parts of such a chunk, // its necessary to know when the chunk is finished, and // we need to move to the next chunk. // if ( pFileByteRange->Length.QuadPart == HTTP_BYTE_RANGE_TO_EOF) { if ( GetFileType( pSourceDataChunk->FromFileHandle.FileHandle ) == FILE_TYPE_DISK ) { if ( !GetFileSizeEx( pSourceDataChunk->FromFileHandle.FileHandle, &lFileSize ) ) { DWORD dwError = GetLastError(); hr = HRESULT_FROM_WIN32(dwError); goto Finished; } // put the resolved file length in the chunk, replacing // HTTP_BYTE_RANGE_TO_EOF pFileByteRange->Length.QuadPart = lFileSize.QuadPart - pFileByteRange->StartingOffset.QuadPart; } else { hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); goto Finished; } } ulTotalLength += pFileByteRange->Length.QuadPart; break; default: // TBD: consider implementing HttpDataChunkFromFragmentCache, // and HttpDataChunkFromFragmentCacheEx hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); goto Finished; } } rsc->m_pResponseBuffer = (char *)apr_palloc(rsc->m_pRequestRec->pool, ulTotalLength); ulTotalLength = 0; for(c = 0; c < pRawHttpResponse->EntityChunkCount; c++ ) { pSourceDataChunk = &pRawHttpResponse->pEntityChunks[ c ]; switch( pSourceDataChunk->DataChunkType ) { case HttpDataChunkFromMemory: memcpy(rsc->m_pResponseBuffer + ulTotalLength, pSourceDataChunk->FromMemory.pBuffer, pSourceDataChunk->FromMemory.BufferLength); ulTotalLength += pSourceDataChunk->FromMemory.BufferLength; break; case HttpDataChunkFromFileHandle: pFileByteRange = &pSourceDataChunk->FromFileHandle.ByteRange; if(ReadFileChunk(pSourceDataChunk, rsc->m_pResponseBuffer + ulTotalLength) != S_OK) { DWORD dwErr = GetLastError(); hr = HRESULT_FROM_WIN32(dwErr); goto Finished; } ulTotalLength += pFileByteRange->Length.QuadPart; break; default: // TBD: consider implementing HttpDataChunkFromFragmentCache, // and HttpDataChunkFromFragmentCacheEx hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); goto Finished; } } rsc->m_pResponseLength = ulTotalLength; // // If there's no content-length set, we need to set it to avoid chunked transfer mode // We can only do it if there is it's the only response to be sent. // DWORD dwFlags = pResponseProvider->GetFlags(); if (pResponseProvider->GetHeadersBeingSent() && (dwFlags & HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0 && pHttpContext->GetResponse()->GetHeader(HttpHeaderContentLength) == NULL) { CHAR szLength[21]; //Max length for a 64 bit int is 20 ZeroMemory(szLength, sizeof(szLength)); hr = StringCchPrintfA( szLength, sizeof(szLength) / sizeof(CHAR) - 1, "%d", ulTotalLength); if(FAILED(hr)) { goto Finished; } hr = pHttpContext->GetResponse()->SetHeader( HttpHeaderContentLength, szLength, (USHORT)strlen(szLength), TRUE); if(FAILED(hr)) { goto Finished; } } Finished: int status = modsecProcessResponse(rsc->m_pRequestRec); // the logic here is temporary, needs clarification // if(status != 0 && status != -1) { pHttpContext->GetResponse()->Clear(); pHttpContext->GetResponse()->SetStatus(status, "ModSecurity Action"); pHttpContext->SetRequestHandled(); rsc->FinishRequest(); LeaveCriticalSection(&m_csLock); return RQ_NOTIFICATION_FINISH_REQUEST; } Exit: // temporary hack, in reality OnSendRequest theoretically could possibly come before OnEndRequest // if(rsc != NULL) rsc->FinishRequest(); LeaveCriticalSection(&m_csLock); return RQ_NOTIFICATION_CONTINUE; }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % E x p o r t K e y r i n g K e y % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ExportKeyringKey() exports a key from the keyring. % % The format of the ExportKeyringKey method is: % % WizardBooleanType ExportKeyringKey(KeyringInfo *keyring_info, % ExceptionInfo *exception) % % A description of each parameter follows: % % o keyring_info: The ring info. % % o exception: Return any errors or warnings in this structure. % */ WizardExport WizardBooleanType ExportKeyringKey(KeyringInfo *keyring_info, ExceptionInfo *exception) { FileInfo *file_info; WizardStatusType status; StringInfo *filetype, *id, *key, *magick, *nonce, *target; size_t length, signature; WizardSizeType timestamp; (void) LogWizardEvent(TraceEvent,GetWizardModule(),"..."); WizardAssert(KeymapDomain,keyring_info != (KeyringInfo *) NULL); WizardAssert(KeymapDomain,keyring_info->signature == WizardSignature); WizardAssert(KeymapDomain,exception != (ExceptionInfo *) NULL); file_info=AcquireFileInfo(keyring_info->path,KeyringFilename,ReadFileMode, exception); if (file_info == (FileInfo *) NULL) return(WizardFalse); magick=GetWizardMagick(WizardMagick,sizeof(WizardMagick)); target=CloneStringInfo(magick); status=ReadFileChunk(file_info,GetStringInfoDatum(target), GetStringInfoLength(target)); if ((status == WizardFalse) || (CompareStringInfo(target,magick) != 0)) { file_info=DestroyFileInfo(file_info,exception); (void) ThrowWizardException(exception,GetWizardModule(),KeyringError, "corrupt key ring file `%s'",GetFilePath(file_info)); return(WizardFalse); } magick=DestroyStringInfo(magick); target=DestroyStringInfo(target); filetype=GetWizardMagick((unsigned char *) KeyringFiletype, strlen(KeyringFiletype)); target=CloneStringInfo(filetype); status&=ReadFileChunk(file_info,GetStringInfoDatum(target), GetStringInfoLength(target)); if ((status == WizardFalse) || (CompareStringInfo(target,filetype) != 0)) { file_info=DestroyFileInfo(file_info,exception); (void) ThrowWizardException(exception,GetWizardModule(),KeyringError, "corrupt key ring file `%s'",GetFilePath(file_info)); return(WizardFalse); } filetype=DestroyStringInfo(filetype); target=DestroyStringInfo(target); signature=0; length=0; while (ReadFile32Bits(file_info,&signature) != 0) { if (signature != WizardSignature) { file_info=DestroyFileInfo(file_info,exception); (void) ThrowWizardException(exception,GetWizardModule(),KeyringError, "corrupt key ring file `%s'",GetFilePath(file_info)); return(WizardFalse); } keyring_info->signature=signature; status&=ReadFile32Bits(file_info,&length); status&=ReadFile16Bits(file_info,&keyring_info->protocol_major); status&=ReadFile16Bits(file_info,&keyring_info->protocol_minor); if ((keyring_info->protocol_major == 1) && (keyring_info->protocol_minor == 0)) timestamp=(time_t) length; else status&=ReadFile64Bits(file_info,×tamp); keyring_info->timestamp=(time_t) timestamp; status&=ReadFile32Bits(file_info,&length); if (status == WizardFalse) { file_info=DestroyFileInfo(file_info,exception); (void) ThrowWizardException(exception,GetWizardModule(),KeyringError, "corrupt key ring file `%s'",GetFilePath(file_info)); return(WizardFalse); } id=AcquireStringInfo(length); status&=ReadFileChunk(file_info,GetStringInfoDatum(id), GetStringInfoLength(id)); status&=ReadFile32Bits(file_info,&length); if (status == WizardFalse) { file_info=DestroyFileInfo(file_info,exception); (void) ThrowWizardException(exception,GetWizardModule(),KeyringError, "corrupt key ring file `%s'",GetFilePath(file_info)); return(WizardFalse); } key=AcquireStringInfo(length); status&=ReadFileChunk(file_info,GetStringInfoDatum(key), GetStringInfoLength(key)); status&=ReadFile32Bits(file_info,&length); if (status == WizardFalse) { file_info=DestroyFileInfo(file_info,exception); (void) ThrowWizardException(exception,GetWizardModule(),KeyringError, "corrupt key ring file `%s'",GetFilePath(file_info)); return(WizardFalse); } nonce=AcquireStringInfo(length); status&=ReadFileChunk(file_info,GetStringInfoDatum(nonce), GetStringInfoLength(nonce)); if (CompareStringInfo(keyring_info->id,id) == 0) { SetKeyringKey(keyring_info,key); SetKeyringNonce(keyring_info,nonce); nonce=DestroyStringInfo(nonce); key=DestroyStringInfo(key); id=DestroyStringInfo(id); file_info=DestroyFileInfo(file_info,exception); return(WizardTrue); } nonce=DestroyStringInfo(nonce); key=DestroyStringInfo(key); id=DestroyStringInfo(id); if (status == WizardFalse) { file_info=DestroyFileInfo(file_info,exception); (void) ThrowWizardException(exception,GetWizardModule(),KeyringError, "corrupt key ring file `%s'",GetFilePath(file_info)); return(WizardFalse); } } file_info=DestroyFileInfo(file_info,exception); return(WizardFalse); }