/*++ Copyright (c) 1995-1996 Microsoft Corporation Module Name : hgetinfo.cxx Abstract: This file contains the code for getting information from HTTP_REQUEST object. This is useful for ISAPI apps and filters. Author: Murali R. Krishnan ( MuraliK ) 20-Nov-1996 Environment: Project: W3Svc DLL Functions Exported: Revision History: --*/ /************************************************************ * Include Headers ************************************************************/ #include "w3p.hxx" extern "C" { #include "md5.h" } // // IsStringMatch() // Matches the given string variable to the constant string supplied. // The two variables involved are strings :( which are null-terminated // So, we cannot apply Memory Comparisons // // Returns: // TRUE on a match // FALSE if there is a failure to match up // # define IsStringMatch( pszConstant, pszVar, cchVar) \ ((cchVar == (sizeof( pszConstant) - 1)) && \ !strcmp( pszConstant, pszVar) \ ) // // IsStringPrefixMatch() // Matches the given string variable for a prefix constant string. // // Returns: // TRUE on a match // FALSE if there is a failure to match up // # define IsStringPrefixMatch( pszConstantPrefix, pszVar, cchVar) \ ((cchVar >= (sizeof( pszConstantPrefix) - 1)) && \ !memcmp( pszConstantPrefix, pszVar, (sizeof(pszConstantPrefix) - 1))\ ) static const CHAR g_szHexDigits[] = "0123456789abcdef"; /************************************************************ * Function Prototypes and inlines ************************************************************/ BOOL BuildCGIHeaderList( HTTP_HEADERS * pHeaderList, CHAR * pchBuffer, DWORD * lpcchBuffer ); BOOL GetInfoFromCertificate( IN TCP_AUTHENT & tcpauth, IN LPCSTR pszValName, DWORD cchValName, OUT CHAR * pchBuffer, IN OUT DWORD * lpcchBuffer ); BOOL HseBuildRawHeaders( IN HTTP_HEADERS * pHeaderList, OUT LPSTR lpvBuffer, IN OUT LPDWORD lpdwSize ); BOOL CopyStringToBuffer( IN LPCSTR psz, IN DWORD cch, OUT CHAR * pchBuffer, IN OUT DWORD * lpcchBuffer ) { if ( *lpcchBuffer >= cch ) { if ( pchBuffer != NULL ) { CopyMemory( pchBuffer, psz, cch); *lpcchBuffer = cch; return (TRUE); } } *lpcchBuffer = cch; SetLastError( ERROR_INSUFFICIENT_BUFFER); return ( FALSE); } // CopyStringToBuffer() BOOL VariableNotAvailable( OUT CHAR* pchBuffer, IN OUT DWORD* lpcchBuffer ) /*++ Description: handles server request for which content is not available, i.e. variables which depends on instance or metadata when such info is not available. In this case we return an empty string. Arguments: pchBuffer - pointer to character buffer which will contain the value if found lpcchBuffer - pointer to DWORD containing IN: the count of characters pchBuffer can store OUT: the count of characters actually stored (on success) the count of characters required (on failure) Returns: TRUE if success, otherwise FALSE Win32 Error Code : NO_ERROR for success ERROR_INSUFFICIENT_BUFFER - if space is not enough ERROR_INVALID_INDEX - if item is not found --*/ { if ( *lpcchBuffer >= 1 ) { if ( pchBuffer != NULL ) { *pchBuffer = '\0'; *lpcchBuffer = 1; return TRUE; } else { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } } *lpcchBuffer = 1; SetLastError( ERROR_INSUFFICIENT_BUFFER); return ( FALSE); } inline BOOL CopyStringToBuffer( IN LPCSTR psz, OUT CHAR * pchBuffer, IN OUT DWORD * lpcchBuffer ) { DBG_ASSERT( psz != NULL ); return (CopyStringToBuffer( psz, strlen(psz) + 1, pchBuffer, lpcchBuffer)); } // CopyStringToBuffer() inline BOOL ReturnNullString( OUT CHAR * pchBuffer, IN OUT DWORD * lpcchBuffer ) { return (CopyStringToBuffer( "", 1, pchBuffer, lpcchBuffer)); } /************************************************************ * Functions ************************************************************/ PW3_METADATA HTTP_REQUEST::GetWAMMetaData( ) /*++ Description: This function gets the metadata pointer taking into account running child ISAPI scenario. For some ISAPI related gets this should be used intstead of QueryMetaData() Arguments: Returns: PW3_METADATA pointer or NULL --*/ { if ( _pWamRequest && _pWamRequest->IsChild() ) { return _pWamRequest->QueryExecMetaData(); } else { return QueryMetaData(); } } BOOL HTTP_REQUEST::GetInfoForName( const CHAR * pszValName, CHAR * pchBuffer, DWORD * lpcchBuffer ) /*++ Description: This function acts as the switch board for getting values for requested ValueName. It is used by Filters/ISAPI applications to obtain the required server and request values. Arguments: pszValName - pointer to string containing the name of the value pchBuffer - pointer to character buffer which will contain the value if found lpcchBuffer - pointer to DWORD containing IN: the count of characters pchBuffer can store OUT: the count of characters actually stored (on success) the count of characters required (on failure) Returns: Win32 Error Code NO_ERROR for success ERROR_INSUFFICIENT_BUFFER - if space is not enough ERROR_INVALID_INDEX - if item is not found --*/ { if ( !pszValName) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } if ( !( *pszValName ) || !isalpha( (UCHAR)(*pszValName) ) ) { SetLastError( ERROR_INVALID_INDEX); return (FALSE); } BOOL fRet; PFN_GET_INFO pfnGI; DWORD cchValName = strlen( pszValName); pfnGI = HTTP_REQUEST::sm_GetInfoFuncs[IndexOfChar(*pszValName)]; DBG_ASSERT( NULL != pfnGI); fRet = (this->*pfnGI)( pszValName, cchValName, pchBuffer, lpcchBuffer ); #if OLD_MODE_COMPATIBILITY // // Once upon a time, this function was not there. Then all the queries // if they did not get resolved were passed onto GetEnvironmentString() // to extract and environment parameter. // // These days the GetEnvironmentString() which is part of the GetInfoMisc() // is not a fast function => it consumes more time // So we will avoid this. Thanks for listening to the story. // if ( !fRet && ( GetLastError() == ERROR_INVALID_INDEX ) ) { // // Try again with the Misc() function if we do not find // the item in the general location. // This has performance costs :( // fRet = GetInfoMisc( pszValName, cchValName, pchBuffer, lpcchBuffer ); } # endif // OLD_MODE_COMPATIBILITY return fRet; } // HTTP_REQUEST::GetInfoForName() BOOL HTTP_REQUEST::GetInfoA( const CHAR * pszValName, DWORD cchValName, CHAR * pchBuffer, DWORD * lpcchBuffer ) { DBG_ASSERT( pszValName != NULL); DBG_ASSERT( toupper(*pszValName) == 'A'); // // ALL_HTTP is a special server specific value used by the CGI code // to retrieve all of the HTTP headers the client sent // if ( IsStringMatch( "ALL_RAW", pszValName, cchValName)) { // // Probably the proxy is making the request // Get the raw list of headers // return ( HseBuildRawHeaders( QueryHeaderList(), pchBuffer, lpcchBuffer) ); } else if ( IsStringMatch( "APPL_MD_PATH", pszValName, cchValName )) { PW3_METADATA pMetaData = GetWAMMetaData(); if ( pMetaData == NULL ) { return VariableNotAvailable( pchBuffer, lpcchBuffer); } DBG_ASSERT( pMetaData->QueryAppPath() != NULL); return ( pMetaData->QueryAppPath()-> CopyToBuffer( pchBuffer, lpcchBuffer) ); } else if ( IsStringMatch( "APPL_PHYSICAL_PATH", pszValName, cchValName )) { PW3_METADATA pMetaData = GetWAMMetaData(); MB mb( (IMDCOM*) g_pInetSvc->QueryMDObject()); if ( pMetaData == NULL ) { return VariableNotAvailable( pchBuffer, lpcchBuffer); } STACK_STR( strAppPhysicalPath, MAX_PATH); // // Create the Applicaiton Physical Path in a separate buffer // and then copy it over to the incoming buffer // return ( ( pMetaData->BuildApplPhysicalPath( &mb, &strAppPhysicalPath)) && strAppPhysicalPath.CopyToBuffer( pchBuffer, lpcchBuffer) ); } else if ( IsStringMatch( "ALL_HTTP", pszValName, cchValName )) { return BuildCGIHeaderList( QueryHeaderList(), pchBuffer, lpcchBuffer ); } else if ( IsStringMatch( "AUTH_TYPE", pszValName, cchValName )) { return ( _strAuthType.CopyToBuffer( pchBuffer, lpcchBuffer)); } else if ( IsStringMatch( "AUTH_PASSWORD", pszValName, cchValName )) { return ( _strUnmappedPassword.CopyToBuffer( pchBuffer, lpcchBuffer)); } else if ( IsStringMatch( "AUTH_USER", pszValName, cchValName )) { return ( _strUnmappedUserName.CopyToBuffer( pchBuffer, lpcchBuffer)); } else { SetLastError( ERROR_INVALID_INDEX); } return ( FALSE); } // HTTP_REQUEST::GetInfoA() BOOL HTTP_REQUEST::GetInfoC( const CHAR * pszValName, DWORD cchValName, CHAR * pchBuffer, DWORD * lpcchBuffer ) { BOOL fReturn; DBG_ASSERT( pszValName != NULL); DBG_ASSERT( toupper(*pszValName) == 'C'); if ( IsStringMatch( "CONTENT_LENGTH", pszValName, cchValName )) { CHAR rgchCL[40]; _ultoa( _cbContentLength, rgchCL, 10); fReturn = CopyStringToBuffer( rgchCL, pchBuffer, lpcchBuffer); } else if ( IsStringMatch( "CONTENT_TYPE", pszValName, cchValName )) { fReturn = _strContentType.CopyToBuffer( pchBuffer, lpcchBuffer); } else if ( IsStringPrefixMatch( "CERT_", pszValName, cchValName)) { // // All the certificates related stuff has to go in here. // fReturn = GetInfoFromCertificate( _tcpauth, (pszValName + 5), cchValName - 5, pchBuffer, lpcchBuffer); } else { SetLastError( ERROR_INVALID_INDEX); fReturn = FALSE; } return ( fReturn); } // HTTP_REQUEST::GetInfoC() BOOL HTTP_REQUEST::GetInfoH( const CHAR * pszValName, DWORD cchValName, CHAR * pchBuffer, DWORD * lpcchBuffer ) { BOOL fReturn = TRUE; LPCSTR pszSuffix; DWORD cchSuffix; DBG_ASSERT( pszValName != NULL); DBG_ASSERT( toupper(*pszValName) == 'H'); if ( IsStringPrefixMatch( "HTTP_", pszValName, cchValName)) { pszSuffix = pszValName + (sizeof("HTTP_") - 1); cchSuffix = cchValName - (sizeof("HTTP_") - 1); if ( IsStringMatch( "REQ_REALM", pszSuffix, cchSuffix)) { LPCSTR psz; // // generate the real information // if ( QueryMetaData() == NULL ) { return VariableNotAvailable( pchBuffer, lpcchBuffer); } psz = ( QueryMetaData()->QueryRealm() ? QueryMetaData()->QueryRealm() : QueryHostAddr() ); fReturn = CopyStringToBuffer( psz, pchBuffer, lpcchBuffer); } else if ( IsStringMatch( "REQ_PWD_EXPIRE", pszSuffix, cchSuffix )) { CHAR rgExp[40]; _ultoa( _dwExpireInDay, rgExp, 10); fReturn = CopyStringToBuffer( rgExp, pchBuffer, lpcchBuffer); } else if ( IsStringMatch( "CFG_ENC_CAPS", pszSuffix, cchSuffix )) { if ( QueryW3Instance() == NULL ) { return VariableNotAvailable( pchBuffer, lpcchBuffer); } CHAR rgNum[40]; _ultoa( (UINT) QueryW3Instance()->QueryEncCaps(), rgNum, 10); fReturn = CopyStringToBuffer( rgNum, pchBuffer, lpcchBuffer); } else { // // Since the value begins with "HTTP_" // then it's probably in our headers list // CHAR achHeader[MAX_HEADER_LENGTH]; CHAR * pch; LPCSTR pszValue; DWORD cchValue; HTTP_FAST_MAP_HEADERS iField; // adjust "1" for the terminating ":" if needed if ( cchSuffix >= sizeof( achHeader ) - 1 ) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } // // Copy the client specified header name to a temp buffer // so we can replace all "_" with "-"s so it will match the // header names in our list. // We also need to append a colon if needed // strcpy( achHeader, pszValName + 5 ); for ( pch = achHeader; pch = strchr( pch, '_' ); *pch++ = '-') ; pszValue = NULL; // Lookup the name in the fast map first. if ( HTTP_HEADERS::FindOrdinalForHeader( achHeader, cchSuffix, (LPDWORD ) &iField) ) { // get the header value from fast map pszValue = _HeaderList.FastMapQueryValue( iField); cchValue = ((pszValue != NULL) ? strlen( pszValue) : 0); } // if the header is absent in the fast map, lookup the slow map if ( NULL == pszValue ) { // append a ':' if not already present if ( (cchSuffix >= 1) && (achHeader[cchSuffix-1] != ':') && (cchSuffix < sizeof(achHeader))) { achHeader[cchSuffix] = ':'; achHeader[cchSuffix+1] = '\0'; cchSuffix++; } pszValue = _HeaderList.FindValue( achHeader, &cchValue ); } if ( pszValue != NULL) { // Copy including the "null" character for the string. fReturn = CopyStringToBuffer( pszValue, cchValue + 1, pchBuffer, lpcchBuffer); } else { SetLastError( ERROR_INVALID_INDEX); fReturn = FALSE; } } } else if ( IsStringPrefixMatch( "HTTPS", pszValName, cchValName)) { pszSuffix = pszValName + (sizeof("HTTPS") - 1); cchSuffix = cchValName - (sizeof("HTTPS") - 1); if ( *pszSuffix == '\0') { // pszValName == "HTTPS" fReturn = CopyStringToBuffer( IsSecurePort() ? "on" : "off", pchBuffer, lpcchBuffer); } else if ( *pszSuffix == '_' ) { fReturn = GetInfoFromCertificate( _tcpauth, pszSuffix+1, cchSuffix - 1, pchBuffer, lpcchBuffer); } else { SetLastError( ERROR_INVALID_INDEX); fReturn = FALSE; } } else { SetLastError( ERROR_INVALID_INDEX); fReturn = FALSE; } return ( fReturn); } // HTTP_REQUEST::GetInfoH() BOOL HTTP_REQUEST::GetInfoI( const CHAR * pszValName, DWORD cchValName, CHAR * pchBuffer, DWORD * lpcchBuffer ) { BOOL fReturn = FALSE; LPCSTR pszSuffix; DWORD cchSuffix; DBG_ASSERT( pszValName != NULL); DBG_ASSERT( toupper(*pszValName) == 'I'); if ( IsStringPrefixMatch( "INSTANCE_", pszValName, cchValName)) { pszSuffix = pszValName + (sizeof("INSTANCE_")-1); cchSuffix = cchValName - (sizeof("INSTANCE_") - 1); if ( IsStringMatch( "ID", pszSuffix, cchSuffix)) { if ( QueryW3Instance() == NULL ) { return VariableNotAvailable( pchBuffer, lpcchBuffer); } CHAR rgch[40]; _ultoa( QueryW3Instance()->QueryInstanceId(), rgch, 10); fReturn = CopyStringToBuffer( rgch, pchBuffer, lpcchBuffer); } else if ( IsStringMatch( "META_PATH", pszSuffix, cchSuffix )) { if ( QueryW3Instance() == NULL ) { return VariableNotAvailable( pchBuffer, lpcchBuffer); } fReturn = CopyStringToBuffer( QueryW3Instance()->QueryMDPath(), pchBuffer, lpcchBuffer); } else { SetLastError( ERROR_INVALID_INDEX); fReturn = FALSE; } } else { SetLastError( ERROR_INVALID_INDEX); fReturn = FALSE; } return fReturn; } // HTTP_REQUEST::GetInfoI() BOOL HTTP_REQUEST::GetInfoL( const CHAR * pszValName, DWORD cchValName, CHAR * pchBuffer, DWORD * lpcchBuffer ) { BOOL fReturn; DBG_ASSERT( pszValName != NULL); DBG_ASSERT( toupper(*pszValName) == 'L'); if ( IsStringMatch( "LOCAL_ADDR", pszValName, cchValName)) { // // Note this returns the server IP address since we don't necessarily // know the DNS name of this server // fReturn = CopyStringToBuffer( QueryClientConn()->QueryLocalAddr(), pchBuffer, lpcchBuffer); } else if ( IsStringMatch( "LOGON_USER", pszValName, cchValName )) { fReturn = _strUserName.CopyToBuffer( pchBuffer, lpcchBuffer); } else { SetLastError( ERROR_INVALID_INDEX); fReturn = FALSE; } return ( fReturn); } // HTTP_REQUEST::GetInfoL() BOOL HTTP_REQUEST::GetInfoP( const CHAR * pszValName, DWORD cchValName, CHAR * pchBuffer, DWORD * lpcchBuffer ) { BOOL fReturn; DBG_ASSERT( pszValName != NULL); DBG_ASSERT( toupper(*pszValName) == 'P'); if ( IsStringMatch( "PATH_INFO", pszValName, cchValName )) { fReturn = _strPathInfo.CopyToBuffer( pchBuffer, lpcchBuffer); } else if ( IsStringMatch( "PATH_TRANSLATED", pszValName, cchValName )) { // // Note that _strPathInfo has already been escaped // // If the path can't be found (no home root for example) then // treat it as success and return the empty string. // // Easiest is to use a string object to obtain the xlation. PW3_METADATA pMetaData = GetWAMMetaData(); if ( pMetaData == NULL ) { return VariableNotAvailable( pchBuffer, lpcchBuffer); } STACK_STR( str, MAX_PATH); if ( !LookupVirtualRoot( &str, _strPathInfo.QueryStr() , _strPathInfo.QueryCCH() ) && GetLastError() != ERROR_PATH_NOT_FOUND ) { fReturn = FALSE; } else { fReturn = str.CopyToBuffer( pchBuffer, lpcchBuffer); } } else { SetLastError( ERROR_INVALID_INDEX); fReturn = FALSE; } return ( fReturn); } // HTTP_REQUEST::GetInfoP() BOOL HTTP_REQUEST::GetInfoR( const CHAR * pszValName, DWORD cchValName, CHAR * pchBuffer, DWORD * lpcchBuffer ) { BOOL fReturn; char chBuff[8]; // plenty of room for _itoa(USHORT_MAX, ...) DBG_ASSERT( pszValName != NULL); DBG_ASSERT( toupper(*pszValName) == 'R'); if ( IsStringMatch( "REQUEST_METHOD", pszValName, cchValName )) { fReturn = _strMethod.CopyToBuffer( pchBuffer, lpcchBuffer); } else if ( IsStringMatch( "REMOTE_HOST", pszValName, cchValName)) { // // Note that REMOTE_HOST returns DNS name if available // fReturn = CopyStringToBuffer( (( QueryClientConn()->IsDnsResolved() )? ( QueryClientConn()->QueryResolvedDnsName()) : ( QueryClientConn()->QueryRemoteAddr() ) ), pchBuffer, lpcchBuffer); } else if ( IsStringMatch( "REMOTE_ADDR", pszValName, cchValName ) ) { fReturn = CopyStringToBuffer( QueryClientConn()->QueryRemoteAddr(), pchBuffer, lpcchBuffer); } else if ( IsStringMatch( "REMOTE_USER", pszValName, cchValName)) { fReturn = _strUnmappedUserName.CopyToBuffer( pchBuffer, lpcchBuffer); } else if ( IsStringMatch( "REMOTE_PORT", pszValName, cchValName ) ) { _itoa( QueryClientConn()->QueryRemotePort(), chBuff, 10); fReturn = CopyStringToBuffer( chBuff, pchBuffer, lpcchBuffer); } else { SetLastError( ERROR_INVALID_INDEX); fReturn = FALSE; } return ( fReturn); } // HTTP_REQUEST::GetInfoR() BOOL HTTP_REQUEST::GetInfoS( const CHAR * pszValName, DWORD cchValName, CHAR * pchBuffer, DWORD * lpcchBuffer ) { BOOL fReturn; DBG_ASSERT( pszValName != NULL); DBG_ASSERT( toupper(*pszValName) == 'S'); if ( IsStringMatch( "SCRIPT_NAME", pszValName, cchValName ) ) { fReturn = _strURL.CopyToBuffer( pchBuffer, lpcchBuffer ); } else if ( IsStringPrefixMatch( "SERVER_", pszValName, cchValName)) { LPCSTR pszSuffix = pszValName + (sizeof("SERVER_") - 1); DWORD cchSuffix = cchValName - (sizeof("SERVER_") - 1); if ( IsStringMatch( "NAME", pszSuffix, cchSuffix ) ) { fReturn = CopyStringToBuffer( QueryHostAddr(), pchBuffer, lpcchBuffer ); } else if ( IsStringMatch( "PROTOCOL", pszSuffix, cchSuffix)) { CHAR rgch[40]; wsprintf( rgch, "HTTP/%d.%d", _VersionMajor, _VersionMinor ); fReturn = CopyStringToBuffer( rgch, pchBuffer, lpcchBuffer); } else if ( IsStringMatch( "PORT", pszSuffix, cchSuffix )) { CHAR rgch[40]; _ultoa( QueryClientConn()->QueryPort(), rgch, 10); fReturn = CopyStringToBuffer( rgch, pchBuffer, lpcchBuffer); } else if ( IsStringMatch( "PORT_SECURE", pszSuffix, cchSuffix)) { fReturn = CopyStringToBuffer( ( IsSecurePort() ? "1" : "0"), 2, pchBuffer, lpcchBuffer ); } else if ( IsStringMatch( "SOFTWARE", pszSuffix, cchSuffix)) { DBG_ASSERT( g_szServerType[g_cbServerType] == '\0'); fReturn = CopyStringToBuffer( g_szServerType, g_cbServerType + 1, pchBuffer, lpcchBuffer); } else { SetLastError( ERROR_INVALID_INDEX); fReturn = FALSE; } } else { SetLastError( ERROR_INVALID_INDEX); fReturn = FALSE; } return ( fReturn); } // HTTP_REQUEST::GetInfoS() BOOL HTTP_REQUEST::GetInfoU( const CHAR * pszValName, DWORD cchValName, CHAR * pchBuffer, DWORD * lpcchBuffer ) { BOOL fReturn; DBG_ASSERT( pszValName != NULL); DBG_ASSERT( toupper(*pszValName) == 'U'); if ( IsStringMatch( "UNMAPPED_REMOTE_USER", pszValName, cchValName )) { fReturn = _strUnmappedUserName.CopyToBuffer( pchBuffer, lpcchBuffer); } else if ( IsStringMatch( "URL", pszValName, cchValName ) ) { fReturn = _strURL.CopyToBuffer( pchBuffer, lpcchBuffer); } else if ( IsStringMatch( "URL_PATH_INFO", pszValName, cchValName ) ) { fReturn = _strURLPathInfo.CopyToBuffer( pchBuffer, lpcchBuffer); } else if ( IsStringMatch( "UNENCODED_URL", pszValName, cchValName ) ) { fReturn = _strRawURL.CopyToBuffer( pchBuffer, lpcchBuffer); } else { SetLastError( ERROR_INVALID_INDEX); fReturn = FALSE; } return ( fReturn); } // HTTP_REQUEST::GetInfoU() BOOL HTTP_REQUEST::GetInfoMisc( const CHAR * pszValName, DWORD cchValName, CHAR * pchBuffer, DWORD * lpcchBuffer ) { BOOL fReturn; DBG_ASSERT( pszValName != NULL); if ( IsStringMatch( "GATEWAY_INTERFACE", pszValName, cchValName )) { fReturn = CopyStringToBuffer( "CGI/1.1", sizeof("CGI/1.1"), pchBuffer, lpcchBuffer); } else if ( IsStringMatch( "QUERY_STRING", pszValName, cchValName )) { fReturn = _strURLParams.CopyToBuffer( pchBuffer, lpcchBuffer); } else { // // Any other value we assume to be a real environment variable // DWORD cch; // // GetEnvironmentVariable() // If the function succeeds, the return value is the number of // characters stored into the buffer pointed to by lpcchBuffer, // not including the terminating null character. // If the specified environment variable name was not found // in the environment block for the current process, // the return value is zero. // If the buffer pointed to by lpcchBuffer is not large enough, // the return value is the buffer size, in characters, // required to hold the value string and its terminating // null character. // cch = GetEnvironmentVariable( pszValName, pchBuffer, *lpcchBuffer); if ( cch == 0) { SetLastError( ERROR_INVALID_INDEX ); fReturn = FALSE; } else if ( cch < *lpcchBuffer ) { // data is already copied. No problems. Return the length. *lpcchBuffer = (cch + 1); fReturn = TRUE; } else { *lpcchBuffer = cch; SetLastError( ERROR_INSUFFICIENT_BUFFER); fReturn = FALSE; } } return (fReturn); } // HTTP_REQUEST::GetInfoMisc() /************************************************************ * Support Functions for GetInfoXXX ************************************************************/ BOOL GetInfoFromCertificate( IN TCP_AUTHENT & tcpauth, IN LPCSTR pszValName, DWORD cchValName, OUT CHAR * pchBuffer, IN OUT DWORD * lpcchBuffer ) { IISMD5_CTX md5; BOOL fReturn = FALSE; BOOL fNoCert; DWORD i; CHAR achCertName[MAX_CERT_FIELD_SIZE]; DWORD dwCertInfo; DBG_ASSERT( pszValName != NULL); DBG_ASSERT( !memcmp( pszValName - 5, "CERT_", 5) || !memcmp( pszValName - 6, "HTTPS_", 6) ); // // Find the value for the field in a certificate that is requested // if ( IsStringMatch( "SUBJECT", pszValName, cchValName )) { LPSTR pV = NULL; if ( !tcpauth.QueryCertificateSubject( achCertName, sizeof(achCertName), &fNoCert ) ) { fReturn = fNoCert ? ReturnNullString( pchBuffer, lpcchBuffer ) : FALSE; } else { fReturn = CopyStringToBuffer( achCertName, pchBuffer, lpcchBuffer); } } else if ( IsStringMatch( "ISSUER", pszValName, cchValName )) { LPSTR pV = NULL; if ( !tcpauth.QueryCertificateIssuer( achCertName, sizeof(achCertName), &fNoCert ) ) { // no certificate available fReturn = fNoCert ? ReturnNullString( pchBuffer, lpcchBuffer ) : FALSE; } else { fReturn = CopyStringToBuffer( achCertName, pchBuffer, lpcchBuffer); } } else if ( IsStringMatch( "FLAGS", pszValName, cchValName )) { DWORD dwF; CHAR rgF[40]; if ( !tcpauth.QueryCertificateFlags( &dwF, &fNoCert ) ) { rgF[0] = '\0'; } else { _ultoa( dwF, rgF, 10); } fReturn = CopyStringToBuffer( rgF, pchBuffer, lpcchBuffer); } else if ( IsStringMatch( "SERIALNUMBER", pszValName, cchValName )) { LPBYTE pV; DWORD cch; // Buffer bytes if ( !tcpauth.QueryCertificateSerialNumber( &pV, &dwCertInfo, &fNoCert ) ) { // no certificate available fReturn = fNoCert ? ReturnNullString( pchBuffer, lpcchBuffer ) : FALSE; } else { // Buffer size (cert bytes * 2 + # of '-' + NULL) cch = dwCertInfo * 3; if ( (pchBuffer == NULL) || (*lpcchBuffer < cch) ) { SetLastError( ERROR_INSUFFICIENT_BUFFER); fReturn = FALSE; } else { // Serial number is in reverse byte order i = 0; for( INT iSerialByte = dwCertInfo - 1; iSerialByte >= 0; --iSerialByte ) { pchBuffer[i++] = g_szHexDigits[ *(pV + iSerialByte) >> 4 ]; pchBuffer[i++] = g_szHexDigits[ *(pV + iSerialByte) & 0xf ]; pchBuffer[i++] = '-'; } DBG_ASSERT(i == cch); pchBuffer[ cch - 1 ] = 0; fReturn = TRUE; } *lpcchBuffer = cch; } } else if ( IsStringMatch( "COOKIE", pszValName, cchValName )) { LPSTR pV; DWORD cch; // Buffer bytes if ( !tcpauth.QueryCertificateIssuer( achCertName, sizeof(achCertName), &fNoCert ) ) { // no certificate available fReturn = fNoCert ? ReturnNullString( pchBuffer, lpcchBuffer ) : FALSE; } else { IISMD5Init( &md5 ); IISMD5Update( &md5, (LPBYTE)achCertName, strlen(achCertName) ); if ( !tcpauth.QueryCertificateSerialNumber( (LPBYTE*)&pV, &dwCertInfo, &fNoCert )) { // assumes that the above call set the error code DBG_ASSERT( fReturn == FALSE); } else { // Buffer size cch = (sizeof(md5.digest) * 2) + 1; if ((pchBuffer == NULL) || (*lpcchBuffer < cch) ) { SetLastError( ERROR_INSUFFICIENT_BUFFER); fReturn = FALSE; } else { IISMD5Update( &md5, (LPBYTE)pV, dwCertInfo ); IISMD5Final( &md5 ); for ( i = 0 ; i < sizeof(md5.digest) ; ++i ) { wsprintf( pchBuffer + i * 2, "%02x", md5.digest[i] ); } fReturn = TRUE; } *lpcchBuffer = cch; } } } else if ( IsStringMatch( "KEYSIZE", pszValName, cchValName)) { DWORD dwVal; CHAR rgVal[40]; if ( !tcpauth.QueryEncryptionKeySize( &dwVal, &fNoCert ) ) { rgVal[0] = '\0'; } else { _ultoa( dwVal, rgVal, 10); } fReturn = CopyStringToBuffer( rgVal, pchBuffer, lpcchBuffer); } else if ( IsStringMatch( "SECRETKEYSIZE", pszValName, cchValName )) { DWORD dwVal; CHAR rgVal[40]; if ( !tcpauth.QueryEncryptionServerPrivateKeySize( &dwVal, &fNoCert ) ) { rgVal[0] = '\0'; } else { _ultoa( dwVal, rgVal, 10); } fReturn = CopyStringToBuffer( rgVal, pchBuffer, lpcchBuffer); } else if ( IsStringMatch( "SERVER_SUBJECT", pszValName, cchValName )) { LPSTR pV; if ( !tcpauth.QueryServerCertificateSubject( &pV, &fNoCert ) ) { // no certificate available fReturn = fNoCert ? ReturnNullString( pchBuffer, lpcchBuffer ) : FALSE; } else { fReturn = CopyStringToBuffer( pV, pchBuffer, lpcchBuffer); } } else if ( IsStringMatch( "SERVER_ISSUER", pszValName, cchValName )) { LPSTR pV; if ( !tcpauth.QueryServerCertificateIssuer( &pV, &fNoCert ) ) { // no certificate available fReturn = fNoCert ? ReturnNullString( pchBuffer, lpcchBuffer ) : FALSE; } else { fReturn = CopyStringToBuffer( pV, pchBuffer, lpcchBuffer); } } else { SetLastError( ERROR_INVALID_INDEX); DBG_ASSERT( fReturn == FALSE); } return ( fReturn); } // GetInfoFromCertificate() # define PSZ_HTTP_PREFIX "HTTP_" # define LEN_PSZ_HTTP_PREFIX (sizeof(PSZ_HTTP_PREFIX) - 1) BOOL BuildCGIHeaderList( HTTP_HEADERS * pHeaderList, CHAR * pchBuffer, DWORD * lpcchBuffer ) /*++ Routine Description: Builds a list of all client passed headers in the form of // // Builds a list of all client HTTP headers in the form of: // // HTTP_: \n // HTTP_: \n // ... // Arguments: pstr - Receives full list pHeaderList - List of headers --*/ { CHAR * pchStart = pchBuffer; DWORD cchReq = 0; BOOL fReturn = TRUE; HH_ITERATOR hhi; NAME_VALUE_PAIR * pnp = NULL; pHeaderList->InitIterator( &hhi); while ( pHeaderList->NextPair( &hhi, &pnp)) { // // Ignore "method", "url" and "version" // if ( pnp->pchName[pnp->cchName - 1] != ':' ) { continue; } // // add HTTP_ as prefix to the headers // convert all "-" to "_" // convert header names to UpperCase // //+1 for terminating '\n' cchReq += (pnp->cchName + pnp->cchValue + 1 + LEN_PSZ_HTTP_PREFIX); if ( pchStart != NULL && cchReq < *lpcchBuffer) { DWORD i; CopyMemory( pchBuffer, PSZ_HTTP_PREFIX, LEN_PSZ_HTTP_PREFIX); pchBuffer += LEN_PSZ_HTTP_PREFIX; // // Convert the destination to upper and replace all '-' with '_' // Also convert lower-case header names to upper-case // for ( i = 0; i < pnp->cchName; i++) { pchBuffer[i] = (( pnp->pchName[i] == '-') ? '_' : toupper( pnp->pchName[i]) ); } // for pchBuffer += i; CopyMemory( (LPVOID) pchBuffer, pnp->pchValue, pnp->cchValue); pchBuffer += pnp->cchValue; *pchBuffer++ = '\n'; // store a \n } else { fReturn = FALSE; } } // while // Store the size depending upon if buffer was sufficient or not if ( fReturn && (pchStart != NULL)) { DBG_ASSERT( pchBuffer >= pchStart); *pchBuffer++ = '\0'; // +1 for '\0' *lpcchBuffer = DIFF(pchBuffer - pchStart); } else { fReturn = FALSE; *lpcchBuffer = cchReq + sizeof(CHAR); SetLastError( ERROR_INSUFFICIENT_BUFFER); } return ( fReturn); } // BuildCGIHeaderList() BOOL HseBuildRawHeaders( IN HTTP_HEADERS * pHeaderList, OUT LPSTR pchBuffer, IN OUT LPDWORD lpcchBuffer ) /*++ Routine Description: Builds a list of all raw client passed headers in the form of
:\n
:\n Arguments: pHeaderList - List of headers pchBuffer - pointer to buffer which will contain generated headers lpcchBuffer - pointer to DWORD containing size of buffer It will contain the size of written data on return. Returns: TRUE on success and FALSE if failure. Error code is set to ERROR_INSUFFICIENT_BUFFER if there is not enough buffer. --*/ { CHAR * pchStart = pchBuffer; DWORD cchReq = 0; BOOL fReturn = TRUE; HH_ITERATOR hhi; NAME_VALUE_PAIR * pnp = NULL; pHeaderList->InitIterator( &hhi); while ( pHeaderList->NextPair( &hhi, &pnp)) { // // Ignore "method", "url" and "version" // if ( pnp->pchName[pnp->cchName - 1] != ':' ) { continue; } // // leave the headers in native form i.e. no conversion of '-' to '_' // cchReq += (pnp->cchName + pnp->cchValue + 3); //+3 for blank & \r\n if ( pchStart != NULL && cchReq < *lpcchBuffer) { CopyMemory( (LPVOID) pchBuffer, pnp->pchName, pnp->cchName * sizeof(CHAR)); pchBuffer += pnp->cchName; *pchBuffer++ = ' '; // store a blank memmove( (LPVOID) pchBuffer, pnp->pchValue, pnp->cchValue); pchBuffer += pnp->cchValue; *pchBuffer++ = '\r'; // store a \r *pchBuffer++ = '\n'; // store a \n } else { fReturn = FALSE; } } // while // Store the size depending upon if buffer was sufficient or not if ( fReturn && (pchStart != NULL)) { DBG_ASSERT( pchBuffer >= pchStart); *pchBuffer++ = '\0'; // +1 for '\0' *lpcchBuffer = DIFF(pchBuffer - pchStart); } else { fReturn = FALSE; *lpcchBuffer = cchReq + sizeof(CHAR); SetLastError( ERROR_INSUFFICIENT_BUFFER); } return (fReturn); } // HseBuildRawHeaders() /************************ End of File ***********************/