Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1403 lines
37 KiB

  1. /*++
  2. Copyright (c) 1995-1996 Microsoft Corporation
  3. Module Name :
  4. hgetinfo.cxx
  5. Abstract:
  6. This file contains the code for getting information from HTTP_REQUEST
  7. object. This is useful for ISAPI apps and filters.
  8. Author:
  9. Murali R. Krishnan ( MuraliK ) 20-Nov-1996
  10. Environment:
  11. Project:
  12. W3Svc DLL
  13. Functions Exported:
  14. Revision History:
  15. --*/
  16. /************************************************************
  17. * Include Headers
  18. ************************************************************/
  19. #include "w3p.hxx"
  20. extern "C"
  21. {
  22. #include "md5.h"
  23. }
  24. //
  25. // IsStringMatch()
  26. // Matches the given string variable to the constant string supplied.
  27. // The two variables involved are strings :( which are null-terminated
  28. // So, we cannot apply Memory Comparisons
  29. //
  30. // Returns:
  31. // TRUE on a match
  32. // FALSE if there is a failure to match up
  33. //
  34. # define IsStringMatch( pszConstant, pszVar, cchVar) \
  35. ((cchVar == (sizeof( pszConstant) - 1)) && \
  36. !strcmp( pszConstant, pszVar) \
  37. )
  38. //
  39. // IsStringPrefixMatch()
  40. // Matches the given string variable for a prefix constant string.
  41. //
  42. // Returns:
  43. // TRUE on a match
  44. // FALSE if there is a failure to match up
  45. //
  46. # define IsStringPrefixMatch( pszConstantPrefix, pszVar, cchVar) \
  47. ((cchVar >= (sizeof( pszConstantPrefix) - 1)) && \
  48. !memcmp( pszConstantPrefix, pszVar, (sizeof(pszConstantPrefix) - 1))\
  49. )
  50. static const CHAR g_szHexDigits[] = "0123456789abcdef";
  51. /************************************************************
  52. * Function Prototypes and inlines
  53. ************************************************************/
  54. BOOL
  55. BuildCGIHeaderList(
  56. HTTP_HEADERS * pHeaderList,
  57. CHAR * pchBuffer,
  58. DWORD * lpcchBuffer
  59. );
  60. BOOL
  61. GetInfoFromCertificate(
  62. IN TCP_AUTHENT & tcpauth,
  63. IN LPCSTR pszValName,
  64. DWORD cchValName,
  65. OUT CHAR * pchBuffer,
  66. IN OUT DWORD * lpcchBuffer
  67. );
  68. BOOL
  69. HseBuildRawHeaders(
  70. IN HTTP_HEADERS * pHeaderList,
  71. OUT LPSTR lpvBuffer,
  72. IN OUT LPDWORD lpdwSize
  73. );
  74. BOOL
  75. CopyStringToBuffer(
  76. IN LPCSTR psz,
  77. IN DWORD cch,
  78. OUT CHAR * pchBuffer,
  79. IN OUT DWORD * lpcchBuffer
  80. )
  81. {
  82. if ( *lpcchBuffer >= cch ) {
  83. if ( pchBuffer != NULL ) {
  84. CopyMemory( pchBuffer, psz, cch);
  85. *lpcchBuffer = cch;
  86. return (TRUE);
  87. }
  88. }
  89. *lpcchBuffer = cch;
  90. SetLastError( ERROR_INSUFFICIENT_BUFFER);
  91. return ( FALSE);
  92. } // CopyStringToBuffer()
  93. BOOL
  94. VariableNotAvailable(
  95. OUT CHAR* pchBuffer,
  96. IN OUT DWORD* lpcchBuffer
  97. )
  98. /*++
  99. Description:
  100. handles server request for which content is not available,
  101. i.e. variables which depends on instance or metadata
  102. when such info is not available.
  103. In this case we return an empty string.
  104. Arguments:
  105. pchBuffer - pointer to character buffer which will contain
  106. the value if found
  107. lpcchBuffer - pointer to DWORD containing
  108. IN: the count of characters pchBuffer can store
  109. OUT: the count of characters actually stored (on success)
  110. the count of characters required (on failure)
  111. Returns:
  112. TRUE if success, otherwise FALSE
  113. Win32 Error Code :
  114. NO_ERROR for success
  115. ERROR_INSUFFICIENT_BUFFER - if space is not enough
  116. ERROR_INVALID_INDEX - if item is not found
  117. --*/
  118. {
  119. if ( *lpcchBuffer >= 1 ) {
  120. if ( pchBuffer != NULL ) {
  121. *pchBuffer = '\0';
  122. *lpcchBuffer = 1;
  123. return TRUE;
  124. } else {
  125. SetLastError( ERROR_INVALID_PARAMETER );
  126. return FALSE;
  127. }
  128. }
  129. *lpcchBuffer = 1;
  130. SetLastError( ERROR_INSUFFICIENT_BUFFER);
  131. return ( FALSE);
  132. }
  133. inline BOOL
  134. CopyStringToBuffer(
  135. IN LPCSTR psz,
  136. OUT CHAR * pchBuffer,
  137. IN OUT DWORD * lpcchBuffer
  138. )
  139. {
  140. DBG_ASSERT( psz != NULL );
  141. return (CopyStringToBuffer( psz, strlen(psz) + 1, pchBuffer, lpcchBuffer));
  142. } // CopyStringToBuffer()
  143. inline BOOL
  144. ReturnNullString(
  145. OUT CHAR * pchBuffer,
  146. IN OUT DWORD * lpcchBuffer
  147. )
  148. {
  149. return (CopyStringToBuffer( "", 1, pchBuffer, lpcchBuffer));
  150. }
  151. /************************************************************
  152. * Functions
  153. ************************************************************/
  154. PW3_METADATA
  155. HTTP_REQUEST::GetWAMMetaData(
  156. )
  157. /*++
  158. Description:
  159. This function gets the metadata pointer taking into account
  160. running child ISAPI scenario. For some ISAPI related gets
  161. this should be used intstead of QueryMetaData()
  162. Arguments:
  163. Returns:
  164. PW3_METADATA pointer or NULL
  165. --*/
  166. {
  167. if ( _pWamRequest && _pWamRequest->IsChild() ) {
  168. return _pWamRequest->QueryExecMetaData();
  169. }
  170. else {
  171. return QueryMetaData();
  172. }
  173. }
  174. BOOL
  175. HTTP_REQUEST::GetInfoForName(
  176. const CHAR * pszValName,
  177. CHAR * pchBuffer,
  178. DWORD * lpcchBuffer
  179. )
  180. /*++
  181. Description:
  182. This function acts as the switch board for getting values
  183. for requested ValueName. It is used by Filters/ISAPI applications
  184. to obtain the required server and request values.
  185. Arguments:
  186. pszValName - pointer to string containing the name of the value
  187. pchBuffer - pointer to character buffer which will contain
  188. the value if found
  189. lpcchBuffer - pointer to DWORD containing
  190. IN: the count of characters pchBuffer can store
  191. OUT: the count of characters actually stored (on success)
  192. the count of characters required (on failure)
  193. Returns:
  194. Win32 Error Code
  195. NO_ERROR for success
  196. ERROR_INSUFFICIENT_BUFFER - if space is not enough
  197. ERROR_INVALID_INDEX - if item is not found
  198. --*/
  199. {
  200. if ( !pszValName)
  201. {
  202. SetLastError( ERROR_INVALID_PARAMETER );
  203. return FALSE;
  204. }
  205. if ( !( *pszValName ) || !isalpha( (UCHAR)(*pszValName) ) )
  206. {
  207. SetLastError( ERROR_INVALID_INDEX);
  208. return (FALSE);
  209. }
  210. BOOL fRet;
  211. PFN_GET_INFO pfnGI;
  212. DWORD cchValName = strlen( pszValName);
  213. pfnGI = HTTP_REQUEST::sm_GetInfoFuncs[IndexOfChar(*pszValName)];
  214. DBG_ASSERT( NULL != pfnGI);
  215. fRet = (this->*pfnGI)( pszValName, cchValName, pchBuffer, lpcchBuffer );
  216. #if OLD_MODE_COMPATIBILITY
  217. //
  218. // Once upon a time, this function was not there. Then all the queries
  219. // if they did not get resolved were passed onto GetEnvironmentString()
  220. // to extract and environment parameter.
  221. //
  222. // These days the GetEnvironmentString() which is part of the GetInfoMisc()
  223. // is not a fast function => it consumes more time
  224. // So we will avoid this. Thanks for listening to the story.
  225. //
  226. if ( !fRet && ( GetLastError() == ERROR_INVALID_INDEX ) )
  227. {
  228. //
  229. // Try again with the Misc() function if we do not find
  230. // the item in the general location.
  231. // This has performance costs :(
  232. //
  233. fRet = GetInfoMisc( pszValName, cchValName,
  234. pchBuffer, lpcchBuffer );
  235. }
  236. # endif // OLD_MODE_COMPATIBILITY
  237. return fRet;
  238. } // HTTP_REQUEST::GetInfoForName()
  239. BOOL
  240. HTTP_REQUEST::GetInfoA(
  241. const CHAR * pszValName,
  242. DWORD cchValName,
  243. CHAR * pchBuffer,
  244. DWORD * lpcchBuffer
  245. )
  246. {
  247. DBG_ASSERT( pszValName != NULL);
  248. DBG_ASSERT( toupper(*pszValName) == 'A');
  249. //
  250. // ALL_HTTP is a special server specific value used by the CGI code
  251. // to retrieve all of the HTTP headers the client sent
  252. //
  253. if ( IsStringMatch( "ALL_RAW", pszValName, cchValName)) {
  254. //
  255. // Probably the proxy is making the request
  256. // Get the raw list of headers
  257. //
  258. return ( HseBuildRawHeaders( QueryHeaderList(),
  259. pchBuffer, lpcchBuffer)
  260. );
  261. } else if ( IsStringMatch( "APPL_MD_PATH", pszValName, cchValName )) {
  262. PW3_METADATA pMetaData = GetWAMMetaData();
  263. if ( pMetaData == NULL )
  264. {
  265. return VariableNotAvailable( pchBuffer, lpcchBuffer);
  266. }
  267. DBG_ASSERT( pMetaData->QueryAppPath() != NULL);
  268. return ( pMetaData->QueryAppPath()->
  269. CopyToBuffer( pchBuffer, lpcchBuffer)
  270. );
  271. } else if ( IsStringMatch( "APPL_PHYSICAL_PATH", pszValName, cchValName )) {
  272. PW3_METADATA pMetaData = GetWAMMetaData();
  273. MB mb( (IMDCOM*) g_pInetSvc->QueryMDObject());
  274. if ( pMetaData == NULL )
  275. {
  276. return VariableNotAvailable( pchBuffer, lpcchBuffer);
  277. }
  278. STACK_STR( strAppPhysicalPath, MAX_PATH);
  279. //
  280. // Create the Applicaiton Physical Path in a separate buffer
  281. // and then copy it over to the incoming buffer
  282. //
  283. return ( ( pMetaData->BuildApplPhysicalPath(
  284. &mb,
  285. &strAppPhysicalPath))
  286. && strAppPhysicalPath.CopyToBuffer( pchBuffer, lpcchBuffer)
  287. );
  288. } else if ( IsStringMatch( "ALL_HTTP", pszValName, cchValName )) {
  289. return BuildCGIHeaderList( QueryHeaderList(), pchBuffer, lpcchBuffer );
  290. } else if ( IsStringMatch( "AUTH_TYPE", pszValName, cchValName )) {
  291. return ( _strAuthType.CopyToBuffer( pchBuffer, lpcchBuffer));
  292. } else if ( IsStringMatch( "AUTH_PASSWORD", pszValName, cchValName )) {
  293. return ( _strUnmappedPassword.CopyToBuffer( pchBuffer, lpcchBuffer));
  294. } else if ( IsStringMatch( "AUTH_USER", pszValName, cchValName )) {
  295. return ( _strUnmappedUserName.CopyToBuffer( pchBuffer, lpcchBuffer));
  296. } else {
  297. SetLastError( ERROR_INVALID_INDEX);
  298. }
  299. return ( FALSE);
  300. } // HTTP_REQUEST::GetInfoA()
  301. BOOL
  302. HTTP_REQUEST::GetInfoC(
  303. const CHAR * pszValName,
  304. DWORD cchValName,
  305. CHAR * pchBuffer,
  306. DWORD * lpcchBuffer
  307. )
  308. {
  309. BOOL fReturn;
  310. DBG_ASSERT( pszValName != NULL);
  311. DBG_ASSERT( toupper(*pszValName) == 'C');
  312. if ( IsStringMatch( "CONTENT_LENGTH", pszValName, cchValName )) {
  313. CHAR rgchCL[40];
  314. _ultoa( _cbContentLength, rgchCL, 10);
  315. fReturn = CopyStringToBuffer( rgchCL,
  316. pchBuffer, lpcchBuffer);
  317. } else if ( IsStringMatch( "CONTENT_TYPE", pszValName, cchValName )) {
  318. fReturn = _strContentType.CopyToBuffer( pchBuffer, lpcchBuffer);
  319. } else if ( IsStringPrefixMatch( "CERT_", pszValName, cchValName)) {
  320. //
  321. // All the certificates related stuff has to go in here.
  322. //
  323. fReturn = GetInfoFromCertificate( _tcpauth, (pszValName + 5),
  324. cchValName - 5,
  325. pchBuffer, lpcchBuffer);
  326. } else {
  327. SetLastError( ERROR_INVALID_INDEX);
  328. fReturn = FALSE;
  329. }
  330. return ( fReturn);
  331. } // HTTP_REQUEST::GetInfoC()
  332. BOOL
  333. HTTP_REQUEST::GetInfoH(
  334. const CHAR * pszValName,
  335. DWORD cchValName,
  336. CHAR * pchBuffer,
  337. DWORD * lpcchBuffer
  338. )
  339. {
  340. BOOL fReturn = TRUE;
  341. LPCSTR pszSuffix;
  342. DWORD cchSuffix;
  343. DBG_ASSERT( pszValName != NULL);
  344. DBG_ASSERT( toupper(*pszValName) == 'H');
  345. if ( IsStringPrefixMatch( "HTTP_", pszValName, cchValName)) {
  346. pszSuffix = pszValName + (sizeof("HTTP_") - 1);
  347. cchSuffix = cchValName - (sizeof("HTTP_") - 1);
  348. if ( IsStringMatch( "REQ_REALM", pszSuffix, cchSuffix)) {
  349. LPCSTR psz;
  350. //
  351. // generate the real information
  352. //
  353. if ( QueryMetaData() == NULL )
  354. {
  355. return VariableNotAvailable( pchBuffer, lpcchBuffer);
  356. }
  357. psz = ( QueryMetaData()->QueryRealm()
  358. ? QueryMetaData()->QueryRealm()
  359. : QueryHostAddr() );
  360. fReturn = CopyStringToBuffer( psz, pchBuffer, lpcchBuffer);
  361. } else if ( IsStringMatch( "REQ_PWD_EXPIRE", pszSuffix, cchSuffix )) {
  362. CHAR rgExp[40];
  363. _ultoa( _dwExpireInDay, rgExp, 10);
  364. fReturn = CopyStringToBuffer( rgExp, pchBuffer, lpcchBuffer);
  365. } else if ( IsStringMatch( "CFG_ENC_CAPS", pszSuffix, cchSuffix )) {
  366. if ( QueryW3Instance() == NULL )
  367. {
  368. return VariableNotAvailable( pchBuffer, lpcchBuffer);
  369. }
  370. CHAR rgNum[40];
  371. _ultoa( (UINT) QueryW3Instance()->QueryEncCaps(),
  372. rgNum, 10);
  373. fReturn = CopyStringToBuffer( rgNum, pchBuffer, lpcchBuffer);
  374. } else {
  375. //
  376. // Since the value begins with "HTTP_"
  377. // then it's probably in our headers list
  378. //
  379. CHAR achHeader[MAX_HEADER_LENGTH];
  380. CHAR * pch;
  381. LPCSTR pszValue;
  382. DWORD cchValue;
  383. HTTP_FAST_MAP_HEADERS iField;
  384. // adjust "1" for the terminating ":" if needed
  385. if ( cchSuffix >= sizeof( achHeader ) - 1 ) {
  386. SetLastError( ERROR_INVALID_PARAMETER );
  387. return FALSE;
  388. }
  389. //
  390. // Copy the client specified header name to a temp buffer
  391. // so we can replace all "_" with "-"s so it will match the
  392. // header names in our list.
  393. // We also need to append a colon if needed
  394. //
  395. strcpy( achHeader, pszValName + 5 );
  396. for ( pch = achHeader; pch = strchr( pch, '_' ); *pch++ = '-')
  397. ;
  398. pszValue = NULL;
  399. // Lookup the name in the fast map first.
  400. if ( HTTP_HEADERS::FindOrdinalForHeader( achHeader, cchSuffix,
  401. (LPDWORD ) &iField)
  402. ) {
  403. // get the header value from fast map
  404. pszValue = _HeaderList.FastMapQueryValue( iField);
  405. cchValue = ((pszValue != NULL) ? strlen( pszValue) : 0);
  406. }
  407. // if the header is absent in the fast map, lookup the slow map
  408. if ( NULL == pszValue ) {
  409. // append a ':' if not already present
  410. if ( (cchSuffix >= 1) && (achHeader[cchSuffix-1] != ':') &&
  411. (cchSuffix < sizeof(achHeader))) {
  412. achHeader[cchSuffix] = ':';
  413. achHeader[cchSuffix+1] = '\0';
  414. cchSuffix++;
  415. }
  416. pszValue = _HeaderList.FindValue( achHeader, &cchValue );
  417. }
  418. if ( pszValue != NULL) {
  419. // Copy including the "null" character for the string.
  420. fReturn = CopyStringToBuffer( pszValue, cchValue + 1,
  421. pchBuffer, lpcchBuffer);
  422. } else {
  423. SetLastError( ERROR_INVALID_INDEX);
  424. fReturn = FALSE;
  425. }
  426. }
  427. } else if ( IsStringPrefixMatch( "HTTPS", pszValName, cchValName)) {
  428. pszSuffix = pszValName + (sizeof("HTTPS") - 1);
  429. cchSuffix = cchValName - (sizeof("HTTPS") - 1);
  430. if ( *pszSuffix == '\0') {
  431. // pszValName == "HTTPS"
  432. fReturn = CopyStringToBuffer( IsSecurePort() ? "on" : "off",
  433. pchBuffer, lpcchBuffer);
  434. } else if ( *pszSuffix == '_' ) {
  435. fReturn = GetInfoFromCertificate( _tcpauth, pszSuffix+1,
  436. cchSuffix - 1,
  437. pchBuffer, lpcchBuffer);
  438. } else {
  439. SetLastError( ERROR_INVALID_INDEX);
  440. fReturn = FALSE;
  441. }
  442. } else {
  443. SetLastError( ERROR_INVALID_INDEX);
  444. fReturn = FALSE;
  445. }
  446. return ( fReturn);
  447. } // HTTP_REQUEST::GetInfoH()
  448. BOOL
  449. HTTP_REQUEST::GetInfoI(
  450. const CHAR * pszValName,
  451. DWORD cchValName,
  452. CHAR * pchBuffer,
  453. DWORD * lpcchBuffer
  454. )
  455. {
  456. BOOL fReturn = FALSE;
  457. LPCSTR pszSuffix;
  458. DWORD cchSuffix;
  459. DBG_ASSERT( pszValName != NULL);
  460. DBG_ASSERT( toupper(*pszValName) == 'I');
  461. if ( IsStringPrefixMatch( "INSTANCE_", pszValName, cchValName))
  462. {
  463. pszSuffix = pszValName + (sizeof("INSTANCE_")-1);
  464. cchSuffix = cchValName - (sizeof("INSTANCE_") - 1);
  465. if ( IsStringMatch( "ID", pszSuffix, cchSuffix))
  466. {
  467. if ( QueryW3Instance() == NULL )
  468. {
  469. return VariableNotAvailable( pchBuffer, lpcchBuffer);
  470. }
  471. CHAR rgch[40];
  472. _ultoa( QueryW3Instance()->QueryInstanceId(),
  473. rgch,
  474. 10);
  475. fReturn = CopyStringToBuffer( rgch, pchBuffer, lpcchBuffer);
  476. }
  477. else if ( IsStringMatch( "META_PATH", pszSuffix, cchSuffix ))
  478. {
  479. if ( QueryW3Instance() == NULL )
  480. {
  481. return VariableNotAvailable( pchBuffer, lpcchBuffer);
  482. }
  483. fReturn = CopyStringToBuffer( QueryW3Instance()->QueryMDPath(),
  484. pchBuffer,
  485. lpcchBuffer);
  486. }
  487. else
  488. {
  489. SetLastError( ERROR_INVALID_INDEX);
  490. fReturn = FALSE;
  491. }
  492. }
  493. else
  494. {
  495. SetLastError( ERROR_INVALID_INDEX);
  496. fReturn = FALSE;
  497. }
  498. return fReturn;
  499. } // HTTP_REQUEST::GetInfoI()
  500. BOOL
  501. HTTP_REQUEST::GetInfoL(
  502. const CHAR * pszValName,
  503. DWORD cchValName,
  504. CHAR * pchBuffer,
  505. DWORD * lpcchBuffer
  506. )
  507. {
  508. BOOL fReturn;
  509. DBG_ASSERT( pszValName != NULL);
  510. DBG_ASSERT( toupper(*pszValName) == 'L');
  511. if ( IsStringMatch( "LOCAL_ADDR", pszValName, cchValName)) {
  512. //
  513. // Note this returns the server IP address since we don't necessarily
  514. // know the DNS name of this server
  515. //
  516. fReturn = CopyStringToBuffer( QueryClientConn()->QueryLocalAddr(),
  517. pchBuffer, lpcchBuffer);
  518. } else if ( IsStringMatch( "LOGON_USER", pszValName, cchValName )) {
  519. fReturn = _strUserName.CopyToBuffer( pchBuffer, lpcchBuffer);
  520. } else {
  521. SetLastError( ERROR_INVALID_INDEX);
  522. fReturn = FALSE;
  523. }
  524. return ( fReturn);
  525. } // HTTP_REQUEST::GetInfoL()
  526. BOOL
  527. HTTP_REQUEST::GetInfoP(
  528. const CHAR * pszValName,
  529. DWORD cchValName,
  530. CHAR * pchBuffer,
  531. DWORD * lpcchBuffer
  532. )
  533. {
  534. BOOL fReturn;
  535. DBG_ASSERT( pszValName != NULL);
  536. DBG_ASSERT( toupper(*pszValName) == 'P');
  537. if ( IsStringMatch( "PATH_INFO", pszValName, cchValName )) {
  538. fReturn = _strPathInfo.CopyToBuffer( pchBuffer, lpcchBuffer);
  539. } else if ( IsStringMatch( "PATH_TRANSLATED", pszValName, cchValName )) {
  540. //
  541. // Note that _strPathInfo has already been escaped
  542. //
  543. // If the path can't be found (no home root for example) then
  544. // treat it as success and return the empty string.
  545. //
  546. // Easiest is to use a string object to obtain the xlation.
  547. PW3_METADATA pMetaData = GetWAMMetaData();
  548. if ( pMetaData == NULL )
  549. {
  550. return VariableNotAvailable( pchBuffer, lpcchBuffer);
  551. }
  552. STACK_STR( str, MAX_PATH);
  553. if ( !LookupVirtualRoot( &str,
  554. _strPathInfo.QueryStr() ,
  555. _strPathInfo.QueryCCH() ) &&
  556. GetLastError() != ERROR_PATH_NOT_FOUND ) {
  557. fReturn = FALSE;
  558. } else {
  559. fReturn = str.CopyToBuffer( pchBuffer, lpcchBuffer);
  560. }
  561. } else {
  562. SetLastError( ERROR_INVALID_INDEX);
  563. fReturn = FALSE;
  564. }
  565. return ( fReturn);
  566. } // HTTP_REQUEST::GetInfoP()
  567. BOOL
  568. HTTP_REQUEST::GetInfoR(
  569. const CHAR * pszValName,
  570. DWORD cchValName,
  571. CHAR * pchBuffer,
  572. DWORD * lpcchBuffer
  573. )
  574. {
  575. BOOL fReturn;
  576. char chBuff[8]; // plenty of room for _itoa(USHORT_MAX, ...)
  577. DBG_ASSERT( pszValName != NULL);
  578. DBG_ASSERT( toupper(*pszValName) == 'R');
  579. if ( IsStringMatch( "REQUEST_METHOD", pszValName, cchValName )) {
  580. fReturn = _strMethod.CopyToBuffer( pchBuffer, lpcchBuffer);
  581. } else if ( IsStringMatch( "REMOTE_HOST", pszValName, cchValName)) {
  582. //
  583. // Note that REMOTE_HOST returns DNS name if available
  584. //
  585. fReturn =
  586. CopyStringToBuffer( (( QueryClientConn()->IsDnsResolved() )?
  587. ( QueryClientConn()->QueryResolvedDnsName()) :
  588. ( QueryClientConn()->QueryRemoteAddr() )
  589. ),
  590. pchBuffer,
  591. lpcchBuffer);
  592. } else if ( IsStringMatch( "REMOTE_ADDR", pszValName, cchValName ) ) {
  593. fReturn = CopyStringToBuffer( QueryClientConn()->QueryRemoteAddr(),
  594. pchBuffer, lpcchBuffer);
  595. } else if ( IsStringMatch( "REMOTE_USER", pszValName, cchValName)) {
  596. fReturn = _strUnmappedUserName.CopyToBuffer( pchBuffer, lpcchBuffer);
  597. } else if ( IsStringMatch( "REMOTE_PORT", pszValName, cchValName ) ) {
  598. _itoa( QueryClientConn()->QueryRemotePort(), chBuff, 10);
  599. fReturn = CopyStringToBuffer( chBuff, pchBuffer, lpcchBuffer);
  600. } else {
  601. SetLastError( ERROR_INVALID_INDEX);
  602. fReturn = FALSE;
  603. }
  604. return ( fReturn);
  605. } // HTTP_REQUEST::GetInfoR()
  606. BOOL
  607. HTTP_REQUEST::GetInfoS(
  608. const CHAR * pszValName,
  609. DWORD cchValName,
  610. CHAR * pchBuffer,
  611. DWORD * lpcchBuffer
  612. )
  613. {
  614. BOOL fReturn;
  615. DBG_ASSERT( pszValName != NULL);
  616. DBG_ASSERT( toupper(*pszValName) == 'S');
  617. if ( IsStringMatch( "SCRIPT_NAME", pszValName, cchValName ) ) {
  618. fReturn = _strURL.CopyToBuffer( pchBuffer, lpcchBuffer );
  619. } else if ( IsStringPrefixMatch( "SERVER_", pszValName, cchValName)) {
  620. LPCSTR pszSuffix = pszValName + (sizeof("SERVER_") - 1);
  621. DWORD cchSuffix = cchValName - (sizeof("SERVER_") - 1);
  622. if ( IsStringMatch( "NAME", pszSuffix, cchSuffix ) ) {
  623. fReturn = CopyStringToBuffer( QueryHostAddr(),
  624. pchBuffer, lpcchBuffer );
  625. } else if ( IsStringMatch( "PROTOCOL", pszSuffix, cchSuffix)) {
  626. CHAR rgch[40];
  627. wsprintf( rgch,
  628. "HTTP/%d.%d",
  629. _VersionMajor,
  630. _VersionMinor );
  631. fReturn = CopyStringToBuffer( rgch, pchBuffer, lpcchBuffer);
  632. } else if ( IsStringMatch( "PORT", pszSuffix, cchSuffix )) {
  633. CHAR rgch[40];
  634. _ultoa( QueryClientConn()->QueryPort(),
  635. rgch, 10);
  636. fReturn = CopyStringToBuffer( rgch, pchBuffer, lpcchBuffer);
  637. } else if ( IsStringMatch( "PORT_SECURE", pszSuffix, cchSuffix)) {
  638. fReturn = CopyStringToBuffer( ( IsSecurePort() ? "1" : "0"), 2,
  639. pchBuffer, lpcchBuffer );
  640. } else if ( IsStringMatch( "SOFTWARE", pszSuffix, cchSuffix)) {
  641. DBG_ASSERT( g_szServerType[g_cbServerType] == '\0');
  642. fReturn = CopyStringToBuffer( g_szServerType, g_cbServerType + 1,
  643. pchBuffer, lpcchBuffer);
  644. } else {
  645. SetLastError( ERROR_INVALID_INDEX);
  646. fReturn = FALSE;
  647. }
  648. } else {
  649. SetLastError( ERROR_INVALID_INDEX);
  650. fReturn = FALSE;
  651. }
  652. return ( fReturn);
  653. } // HTTP_REQUEST::GetInfoS()
  654. BOOL
  655. HTTP_REQUEST::GetInfoU(
  656. const CHAR * pszValName,
  657. DWORD cchValName,
  658. CHAR * pchBuffer,
  659. DWORD * lpcchBuffer
  660. )
  661. {
  662. BOOL fReturn;
  663. DBG_ASSERT( pszValName != NULL);
  664. DBG_ASSERT( toupper(*pszValName) == 'U');
  665. if ( IsStringMatch( "UNMAPPED_REMOTE_USER", pszValName, cchValName )) {
  666. fReturn = _strUnmappedUserName.CopyToBuffer( pchBuffer, lpcchBuffer);
  667. } else if ( IsStringMatch( "URL", pszValName, cchValName ) ) {
  668. fReturn = _strURL.CopyToBuffer( pchBuffer, lpcchBuffer);
  669. } else if ( IsStringMatch( "URL_PATH_INFO", pszValName, cchValName ) ) {
  670. fReturn = _strURLPathInfo.CopyToBuffer( pchBuffer, lpcchBuffer);
  671. } else if ( IsStringMatch( "UNENCODED_URL", pszValName, cchValName ) ) {
  672. fReturn = _strRawURL.CopyToBuffer( pchBuffer, lpcchBuffer);
  673. }
  674. else {
  675. SetLastError( ERROR_INVALID_INDEX);
  676. fReturn = FALSE;
  677. }
  678. return ( fReturn);
  679. } // HTTP_REQUEST::GetInfoU()
  680. BOOL
  681. HTTP_REQUEST::GetInfoMisc(
  682. const CHAR * pszValName,
  683. DWORD cchValName,
  684. CHAR * pchBuffer,
  685. DWORD * lpcchBuffer
  686. )
  687. {
  688. BOOL fReturn;
  689. DBG_ASSERT( pszValName != NULL);
  690. if ( IsStringMatch( "GATEWAY_INTERFACE", pszValName, cchValName )) {
  691. fReturn = CopyStringToBuffer( "CGI/1.1", sizeof("CGI/1.1"),
  692. pchBuffer, lpcchBuffer);
  693. } else if ( IsStringMatch( "QUERY_STRING", pszValName, cchValName )) {
  694. fReturn = _strURLParams.CopyToBuffer( pchBuffer, lpcchBuffer);
  695. } else {
  696. //
  697. // Any other value we assume to be a real environment variable
  698. //
  699. DWORD cch;
  700. //
  701. // GetEnvironmentVariable()
  702. // If the function succeeds, the return value is the number of
  703. // characters stored into the buffer pointed to by lpcchBuffer,
  704. // not including the terminating null character.
  705. // If the specified environment variable name was not found
  706. // in the environment block for the current process,
  707. // the return value is zero.
  708. // If the buffer pointed to by lpcchBuffer is not large enough,
  709. // the return value is the buffer size, in characters,
  710. // required to hold the value string and its terminating
  711. // null character.
  712. //
  713. cch = GetEnvironmentVariable( pszValName,
  714. pchBuffer,
  715. *lpcchBuffer);
  716. if ( cch == 0) {
  717. SetLastError( ERROR_INVALID_INDEX );
  718. fReturn = FALSE;
  719. } else if ( cch < *lpcchBuffer ) {
  720. // data is already copied. No problems. Return the length.
  721. *lpcchBuffer = (cch + 1);
  722. fReturn = TRUE;
  723. } else {
  724. *lpcchBuffer = cch;
  725. SetLastError( ERROR_INSUFFICIENT_BUFFER);
  726. fReturn = FALSE;
  727. }
  728. }
  729. return (fReturn);
  730. } // HTTP_REQUEST::GetInfoMisc()
  731. /************************************************************
  732. * Support Functions for GetInfoXXX
  733. ************************************************************/
  734. BOOL
  735. GetInfoFromCertificate(
  736. IN TCP_AUTHENT & tcpauth,
  737. IN LPCSTR pszValName,
  738. DWORD cchValName,
  739. OUT CHAR * pchBuffer,
  740. IN OUT DWORD * lpcchBuffer
  741. )
  742. {
  743. IISMD5_CTX md5;
  744. BOOL fReturn = FALSE;
  745. BOOL fNoCert;
  746. DWORD i;
  747. CHAR achCertName[MAX_CERT_FIELD_SIZE];
  748. DWORD dwCertInfo;
  749. DBG_ASSERT( pszValName != NULL);
  750. DBG_ASSERT( !memcmp( pszValName - 5, "CERT_", 5) ||
  751. !memcmp( pszValName - 6, "HTTPS_", 6)
  752. );
  753. //
  754. // Find the value for the field in a certificate that is requested
  755. //
  756. if ( IsStringMatch( "SUBJECT", pszValName, cchValName )) {
  757. LPSTR pV = NULL;
  758. if ( !tcpauth.QueryCertificateSubject( achCertName, sizeof(achCertName), &fNoCert ) ) {
  759. fReturn = fNoCert ? ReturnNullString( pchBuffer, lpcchBuffer ) : FALSE;
  760. } else {
  761. fReturn = CopyStringToBuffer( achCertName, pchBuffer, lpcchBuffer);
  762. }
  763. } else if ( IsStringMatch( "ISSUER", pszValName, cchValName )) {
  764. LPSTR pV = NULL;
  765. if ( !tcpauth.QueryCertificateIssuer( achCertName, sizeof(achCertName), &fNoCert ) ) {
  766. // no certificate available
  767. fReturn = fNoCert ? ReturnNullString( pchBuffer, lpcchBuffer ) : FALSE;
  768. } else {
  769. fReturn = CopyStringToBuffer( achCertName, pchBuffer, lpcchBuffer);
  770. }
  771. } else if ( IsStringMatch( "FLAGS", pszValName, cchValName )) {
  772. DWORD dwF;
  773. CHAR rgF[40];
  774. if ( !tcpauth.QueryCertificateFlags( &dwF, &fNoCert ) ) {
  775. rgF[0] = '\0';
  776. } else {
  777. _ultoa( dwF, rgF, 10);
  778. }
  779. fReturn = CopyStringToBuffer( rgF, pchBuffer, lpcchBuffer);
  780. } else if ( IsStringMatch( "SERIALNUMBER", pszValName, cchValName )) {
  781. LPBYTE pV;
  782. DWORD cch; // Buffer bytes
  783. if ( !tcpauth.QueryCertificateSerialNumber( &pV, &dwCertInfo, &fNoCert ) ) {
  784. // no certificate available
  785. fReturn = fNoCert ? ReturnNullString( pchBuffer, lpcchBuffer ) : FALSE;
  786. } else {
  787. // Buffer size (cert bytes * 2 + # of '-' + NULL)
  788. cch = dwCertInfo * 3;
  789. if ( (pchBuffer == NULL) || (*lpcchBuffer < cch) )
  790. {
  791. SetLastError( ERROR_INSUFFICIENT_BUFFER);
  792. fReturn = FALSE;
  793. }
  794. else
  795. {
  796. // Serial number is in reverse byte order
  797. i = 0;
  798. for( INT iSerialByte = dwCertInfo - 1; iSerialByte >= 0; --iSerialByte )
  799. {
  800. pchBuffer[i++] = g_szHexDigits[ *(pV + iSerialByte) >> 4 ];
  801. pchBuffer[i++] = g_szHexDigits[ *(pV + iSerialByte) & 0xf ];
  802. pchBuffer[i++] = '-';
  803. }
  804. DBG_ASSERT(i == cch);
  805. pchBuffer[ cch - 1 ] = 0;
  806. fReturn = TRUE;
  807. }
  808. *lpcchBuffer = cch;
  809. }
  810. } else if ( IsStringMatch( "COOKIE", pszValName, cchValName )) {
  811. LPSTR pV;
  812. DWORD cch; // Buffer bytes
  813. if ( !tcpauth.QueryCertificateIssuer( achCertName, sizeof(achCertName), &fNoCert ) ) {
  814. // no certificate available
  815. fReturn = fNoCert ? ReturnNullString( pchBuffer, lpcchBuffer ) : FALSE;
  816. } else {
  817. IISMD5Init( &md5 );
  818. IISMD5Update( &md5, (LPBYTE)achCertName, strlen(achCertName) );
  819. if ( !tcpauth.QueryCertificateSerialNumber( (LPBYTE*)&pV, &dwCertInfo, &fNoCert )) {
  820. // assumes that the above call set the error code
  821. DBG_ASSERT( fReturn == FALSE);
  822. } else {
  823. // Buffer size
  824. cch = (sizeof(md5.digest) * 2) + 1;
  825. if ((pchBuffer == NULL) || (*lpcchBuffer < cch) )
  826. {
  827. SetLastError( ERROR_INSUFFICIENT_BUFFER);
  828. fReturn = FALSE;
  829. }
  830. else
  831. {
  832. IISMD5Update( &md5, (LPBYTE)pV, dwCertInfo );
  833. IISMD5Final( &md5 );
  834. for ( i = 0 ; i < sizeof(md5.digest) ; ++i ) {
  835. wsprintf( pchBuffer + i * 2, "%02x", md5.digest[i] );
  836. }
  837. fReturn = TRUE;
  838. }
  839. *lpcchBuffer = cch;
  840. }
  841. }
  842. } else if ( IsStringMatch( "KEYSIZE", pszValName, cchValName)) {
  843. DWORD dwVal;
  844. CHAR rgVal[40];
  845. if ( !tcpauth.QueryEncryptionKeySize( &dwVal, &fNoCert ) ) {
  846. rgVal[0] = '\0';
  847. } else {
  848. _ultoa( dwVal, rgVal, 10);
  849. }
  850. fReturn = CopyStringToBuffer( rgVal, pchBuffer, lpcchBuffer);
  851. } else if ( IsStringMatch( "SECRETKEYSIZE", pszValName, cchValName )) {
  852. DWORD dwVal;
  853. CHAR rgVal[40];
  854. if ( !tcpauth.QueryEncryptionServerPrivateKeySize( &dwVal, &fNoCert ) ) {
  855. rgVal[0] = '\0';
  856. } else {
  857. _ultoa( dwVal, rgVal, 10);
  858. }
  859. fReturn = CopyStringToBuffer( rgVal, pchBuffer, lpcchBuffer);
  860. } else if ( IsStringMatch( "SERVER_SUBJECT", pszValName, cchValName )) {
  861. LPSTR pV;
  862. if ( !tcpauth.QueryServerCertificateSubject( &pV, &fNoCert ) ) {
  863. // no certificate available
  864. fReturn = fNoCert ? ReturnNullString( pchBuffer, lpcchBuffer ) : FALSE;
  865. } else {
  866. fReturn = CopyStringToBuffer( pV, pchBuffer, lpcchBuffer);
  867. }
  868. } else if ( IsStringMatch( "SERVER_ISSUER", pszValName, cchValName )) {
  869. LPSTR pV;
  870. if ( !tcpauth.QueryServerCertificateIssuer( &pV, &fNoCert ) ) {
  871. // no certificate available
  872. fReturn = fNoCert ? ReturnNullString( pchBuffer, lpcchBuffer ) : FALSE;
  873. } else {
  874. fReturn = CopyStringToBuffer( pV, pchBuffer, lpcchBuffer);
  875. }
  876. } else {
  877. SetLastError( ERROR_INVALID_INDEX);
  878. DBG_ASSERT( fReturn == FALSE);
  879. }
  880. return ( fReturn);
  881. } // GetInfoFromCertificate()
  882. # define PSZ_HTTP_PREFIX "HTTP_"
  883. # define LEN_PSZ_HTTP_PREFIX (sizeof(PSZ_HTTP_PREFIX) - 1)
  884. BOOL
  885. BuildCGIHeaderList(
  886. HTTP_HEADERS * pHeaderList,
  887. CHAR * pchBuffer,
  888. DWORD * lpcchBuffer
  889. )
  890. /*++
  891. Routine Description:
  892. Builds a list of all client passed headers in the form of
  893. //
  894. // Builds a list of all client HTTP headers in the form of:
  895. //
  896. // HTTP_<up-case header>: <field>\n
  897. // HTTP_<up-case header>: <field>\n
  898. // ...
  899. //
  900. Arguments:
  901. pstr - Receives full list
  902. pHeaderList - List of headers
  903. --*/
  904. {
  905. CHAR * pchStart = pchBuffer;
  906. DWORD cchReq = 0;
  907. BOOL fReturn = TRUE;
  908. HH_ITERATOR hhi;
  909. NAME_VALUE_PAIR * pnp = NULL;
  910. pHeaderList->InitIterator( &hhi);
  911. while ( pHeaderList->NextPair( &hhi, &pnp)) {
  912. //
  913. // Ignore "method", "url" and "version"
  914. //
  915. if ( pnp->pchName[pnp->cchName - 1] != ':' ) {
  916. continue;
  917. }
  918. //
  919. // add HTTP_ as prefix to the headers
  920. // convert all "-" to "_"
  921. // convert header names to UpperCase
  922. //
  923. //+1 for terminating '\n'
  924. cchReq += (pnp->cchName + pnp->cchValue + 1 + LEN_PSZ_HTTP_PREFIX);
  925. if ( pchStart != NULL && cchReq < *lpcchBuffer) {
  926. DWORD i;
  927. CopyMemory( pchBuffer, PSZ_HTTP_PREFIX, LEN_PSZ_HTTP_PREFIX);
  928. pchBuffer += LEN_PSZ_HTTP_PREFIX;
  929. //
  930. // Convert the destination to upper and replace all '-' with '_'
  931. // Also convert lower-case header names to upper-case
  932. //
  933. for ( i = 0; i < pnp->cchName; i++) {
  934. pchBuffer[i] = (( pnp->pchName[i] == '-') ? '_' :
  935. toupper( pnp->pchName[i])
  936. );
  937. } // for
  938. pchBuffer += i;
  939. CopyMemory( (LPVOID) pchBuffer, pnp->pchValue, pnp->cchValue);
  940. pchBuffer += pnp->cchValue;
  941. *pchBuffer++ = '\n'; // store a \n
  942. } else {
  943. fReturn = FALSE;
  944. }
  945. } // while
  946. // Store the size depending upon if buffer was sufficient or not
  947. if ( fReturn && (pchStart != NULL)) {
  948. DBG_ASSERT( pchBuffer >= pchStart);
  949. *pchBuffer++ = '\0'; // +1 for '\0'
  950. *lpcchBuffer = DIFF(pchBuffer - pchStart);
  951. } else {
  952. fReturn = FALSE;
  953. *lpcchBuffer = cchReq + sizeof(CHAR);
  954. SetLastError( ERROR_INSUFFICIENT_BUFFER);
  955. }
  956. return ( fReturn);
  957. } // BuildCGIHeaderList()
  958. BOOL
  959. HseBuildRawHeaders( IN HTTP_HEADERS * pHeaderList,
  960. OUT LPSTR pchBuffer,
  961. IN OUT LPDWORD lpcchBuffer
  962. )
  963. /*++
  964. Routine Description:
  965. Builds a list of all raw client passed headers in the form of
  966. <header>:<blank><field>\n
  967. <header>:<blank><field>\n
  968. Arguments:
  969. pHeaderList - List of headers
  970. pchBuffer - pointer to buffer which will contain generated headers
  971. lpcchBuffer - pointer to DWORD containing size of buffer
  972. It will contain the size of written data on return.
  973. Returns:
  974. TRUE on success and FALSE if failure.
  975. Error code is set to ERROR_INSUFFICIENT_BUFFER
  976. if there is not enough buffer.
  977. --*/
  978. {
  979. CHAR * pchStart = pchBuffer;
  980. DWORD cchReq = 0;
  981. BOOL fReturn = TRUE;
  982. HH_ITERATOR hhi;
  983. NAME_VALUE_PAIR * pnp = NULL;
  984. pHeaderList->InitIterator( &hhi);
  985. while ( pHeaderList->NextPair( &hhi, &pnp)) {
  986. //
  987. // Ignore "method", "url" and "version"
  988. //
  989. if ( pnp->pchName[pnp->cchName - 1] != ':' ) {
  990. continue;
  991. }
  992. //
  993. // leave the headers in native form i.e. no conversion of '-' to '_'
  994. //
  995. cchReq += (pnp->cchName + pnp->cchValue + 3); //+3 for blank & \r\n
  996. if ( pchStart != NULL && cchReq < *lpcchBuffer) {
  997. CopyMemory( (LPVOID) pchBuffer, pnp->pchName,
  998. pnp->cchName * sizeof(CHAR));
  999. pchBuffer += pnp->cchName;
  1000. *pchBuffer++ = ' '; // store a blank
  1001. memmove( (LPVOID) pchBuffer, pnp->pchValue, pnp->cchValue);
  1002. pchBuffer += pnp->cchValue;
  1003. *pchBuffer++ = '\r'; // store a \r
  1004. *pchBuffer++ = '\n'; // store a \n
  1005. } else {
  1006. fReturn = FALSE;
  1007. }
  1008. } // while
  1009. // Store the size depending upon if buffer was sufficient or not
  1010. if ( fReturn && (pchStart != NULL)) {
  1011. DBG_ASSERT( pchBuffer >= pchStart);
  1012. *pchBuffer++ = '\0'; // +1 for '\0'
  1013. *lpcchBuffer = DIFF(pchBuffer - pchStart);
  1014. } else {
  1015. fReturn = FALSE;
  1016. *lpcchBuffer = cchReq + sizeof(CHAR);
  1017. SetLastError( ERROR_INSUFFICIENT_BUFFER);
  1018. }
  1019. return (fReturn);
  1020. } // HseBuildRawHeaders()
  1021. /************************ End of File ***********************/