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.

4124 lines
105 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows NT **/
  3. /** Copyright(c) Microsoft Corp., 1994 **/
  4. /**********************************************************************/
  5. /*
  6. basereq.cxx
  7. This module contains the http base request class implementation
  8. FILE HISTORY:
  9. Johnl 24-Aug-1994 Created
  10. MuraliK 16-May-1995 Modified LogInformation structure
  11. after adding additional fields.
  12. MuraliK 13-Oct-1995 Created basereq file from old httreq.cxx
  13. */
  14. #include "w3p.hxx"
  15. #include <inetinfo.h>
  16. #include "basereq.hxx"
  17. #include <lonsi.hxx>
  18. #include <stdlib.h>
  19. #include <errno.h>
  20. #include <limits.h>
  21. #include <iscaptrc.h>
  22. #pragma warning( disable:4355 ) // 'this' used in base member initialization
  23. //
  24. // Private constants.
  25. //
  26. //
  27. // Default response buffer size
  28. //
  29. #define DEF_RESP_BUFF_SIZE 4096
  30. //
  31. // minimum buffer size after custom headers
  32. //
  33. #define POST_CUSTOM_HEADERS_SIZE 256
  34. //
  35. // We cache our read and write buffers but if they get beyond this size, we
  36. // free it and start from scratch on the next request
  37. //
  38. #define MAX_CLIENT_SIZE_ALLOWED (4 * 4096)
  39. //
  40. // Handle used to indicate request to deny access to current HTTP request
  41. //
  42. #define IIS_ACCESS_DENIED_HANDLE ((HANDLE)1)
  43. //
  44. // Public functions.
  45. //
  46. //
  47. // Private functions.
  48. //
  49. #define CONST_TO_STRING(x) #x
  50. HTTP_REQ_BASE::HTTP_REQ_BASE(
  51. CLIENT_CONN * pClientConn,
  52. PVOID pvInitialBuff,
  53. DWORD cbInitialBuff
  54. ) :
  55. _tcpauth ( TCPAUTH_SERVER | TCPAUTH_UUENCODE ),
  56. _Filter ( this ),
  57. _fValid ( FALSE ),
  58. _bufServerResp ( DEF_RESP_BUFF_SIZE ),
  59. _dwLogHttpResponse ( HT_DONT_LOG ),
  60. _pURIInfo ( NULL ),
  61. _pMetaData ( NULL )
  62. {
  63. #if defined(CAL_ENABLED)
  64. m_pCalAuthCtxt = NULL;
  65. m_pCalSslCtxt = NULL;
  66. #endif
  67. InitializeSession( pClientConn,
  68. pvInitialBuff,
  69. cbInitialBuff );
  70. DBG_ASSERT( pClientConn->CheckSignature() );
  71. if ( !_Filter.IsValid() ||
  72. !_bufServerResp.QueryPtr() )
  73. {
  74. return;
  75. }
  76. _acIpAccess = AC_NOT_CHECKED;
  77. _fNeedDnsCheck = FALSE;
  78. _fValid = TRUE;
  79. }
  80. VOID
  81. HTTP_REQ_BASE::InitializeSession(
  82. CLIENT_CONN * pClientConn,
  83. PVOID pvInitialBuff,
  84. DWORD cbInitialBuff
  85. )
  86. /*++
  87. Routine Description:
  88. This is a pseudo constructor called by the buffer list code.
  89. This routine should initialize all of the items that should be reset
  90. between TCP sessions (but may remain valid over multiple requests on the
  91. same TCP session, i.e., "Connection: keep-alive")
  92. Arguments:
  93. pClientConn - Client connection object we're speaking to
  94. --*/
  95. {
  96. _pClientConn = pClientConn;
  97. _pW3Instance = NULL;
  98. _pW3Stats = g_pW3Stats;
  99. _fKeepConn = FALSE;
  100. _fSecurePort = pClientConn->IsSecurePort();
  101. ResetAuth( TRUE );
  102. _fSingleRequestAuth = FALSE;
  103. _cFilesSent = 0;
  104. _cFilesReceived = 0;
  105. _cbBytesSent = 0;
  106. _cbBytesReceived = 0;
  107. _cbTotalBytesSent = 0;
  108. _cbTotalBytesReceived= 0;
  109. _fAsyncSendPosted = FALSE;
  110. _Filter.Reset();
  111. _pAuthFilter = NULL;
  112. _strHostAddr.Reset();
  113. _dwRenegotiated = 0;
  114. _dwSslNegoFlags = 0;
  115. IF_DEBUG(REQUEST) {
  116. DBGPRINTF(( DBG_CONTEXT,
  117. "[InitializeSession] time=%u HTTP=%08x\n",
  118. GetTickCount(), (LPVOID)this
  119. ));
  120. }
  121. }
  122. HTTP_REQ_BASE::~HTTP_REQ_BASE( VOID )
  123. {
  124. }
  125. BOOL
  126. HTTP_REQ_BASE::ResetAuth(
  127. BOOL fSessionReset
  128. )
  129. /*++
  130. Routine Description:
  131. This method is called to reset authentication status.
  132. Arguments:
  133. None
  134. --*/
  135. {
  136. TCP_REQUIRE( _tcpauth.Reset( fSessionReset ) );
  137. _fClearTextPass = FALSE;
  138. _fAnonymous = FALSE;
  139. _fMappedAcct = FALSE;
  140. _fAuthenticating = FALSE;
  141. _fLoggedOn = FALSE;
  142. _fInvalidAccessToken = FALSE;
  143. _fAuthTypeDigest = FALSE;
  144. _fAuthSystem = FALSE;
  145. _fAuthCert = FALSE;
  146. _cbLastAnonAcctDesc = 0;
  147. _strAuthType.Reset();
  148. _strUserName.Reset();
  149. _strPassword.Reset();
  150. _strUnmappedUserName.Reset();
  151. _strUnmappedPassword.Reset();
  152. _fSingleRequestAuth = FALSE;
  153. #if defined(CAL_ENABLED)
  154. if ( m_pCalAuthCtxt )
  155. {
  156. CalDisconnect( m_pCalAuthCtxt );
  157. m_pCalAuthCtxt = NULL;
  158. }
  159. #endif
  160. return TRUE;
  161. }
  162. BOOL
  163. HTTP_REQ_BASE::Reset(
  164. BOOL fResetPipelineInfo
  165. )
  166. /*++
  167. Routine Description:
  168. This method is called after an individual request has been processed.
  169. If the session is being kept open, this object can be used again for
  170. the next request on this TCP session. In this case, various items such
  171. as authentication information etc. remain valid.
  172. The method is also called once when the object is first allocated.
  173. Arguments:
  174. --*/
  175. {
  176. _fStartTimeValid = FALSE;
  177. _VersionMajor = 0;
  178. _VersionMinor = 0;
  179. _cbEntityBody = 0;
  180. _cbTotalEntityBody = 0;
  181. _cbContentLength = 0;
  182. _cbClientRequest = 0;
  183. if (fResetPipelineInfo)
  184. {
  185. _cbOldData = 0;
  186. }
  187. else if (_cbOldData > 0)
  188. {
  189. _cbOldData -= _cbBytesReceived;
  190. }
  191. _cbExtraData = 0;
  192. _pchExtraData = NULL;
  193. _liModifiedSince.QuadPart = 0;
  194. _liUnlessModifiedSince.QuadPart = 0;
  195. _liUnmodifiedSince.QuadPart = 0;
  196. _dwModifiedSinceLength = 0;
  197. _status = NO_ERROR;
  198. _cbBytesWritten = 0;
  199. _HeaderList.Reset();
  200. _Filter.Reset();
  201. //
  202. // Reset our statistics for this request
  203. //
  204. _cbTotalBytesSent += _cbBytesSent;
  205. _cbTotalBytesReceived += _cbBytesReceived;
  206. _cbBytesSent = 0;
  207. _cbBytesReceived = 0;
  208. _fAsyncSendPosted = FALSE;
  209. //
  210. // Don't log this request unless we're explicity indicated a status
  211. //
  212. _dwLogHttpResponse = HT_DONT_LOG;
  213. _dwLogWinError = NO_ERROR;
  214. _strURL.Reset();
  215. _strURLPathInfo.Reset();
  216. _strURLParams.Reset();
  217. _strLogParams.Reset();
  218. _strPathInfo.Reset();
  219. _strRawURL.Reset();
  220. _strOriginalURL.Reset();
  221. _strMethod.Reset();
  222. _strAuthInfo.Reset();
  223. _strPhysicalPath.Reset();
  224. _strUnmappedPhysicalPath.Reset();
  225. _strDenialHdrs.Reset();
  226. _strRespHdrs.Reset();
  227. _strRange.Reset();
  228. _bProcessingCustomError = FALSE;
  229. _bForceNoCache = FALSE;
  230. _bSendContentLocation = FALSE;
  231. _bSendVary = FALSE;
  232. ClearNoCache();
  233. ClearSendCL();
  234. ClearSendVary();
  235. _fAuthenticationRequested = FALSE;
  236. _fProxyRequest = FALSE;
  237. _fBasicRealm = FALSE;
  238. _fIfModifier = FALSE;
  239. _fHaveContentLength = FALSE;
  240. _fLogRecordWritten = FALSE;
  241. _dwExpireInDay = 0x7fffffff;
  242. if ( _fSingleRequestAuth )
  243. {
  244. LPW3_SERVER_STATISTICS pStatsObj = QueryW3StatsObj();
  245. pStatsObj->DecrCurrentNonAnonymousUsers();
  246. ResetAuth( FALSE );
  247. _fSingleRequestAuth = FALSE;
  248. }
  249. // Accept range variables
  250. _fProcessByteRange = FALSE;
  251. _fUnsatisfiableByteRange = FALSE;
  252. _fAcceptRange = FALSE;
  253. _iRangeIdx = 0;
  254. _cbMimeMultipart = 0;
  255. _fMimeMultipart = FALSE;
  256. _acIpAccess = AC_NOT_CHECKED;
  257. _fNeedDnsCheck = FALSE;
  258. _fChunked = FALSE;
  259. #if 0 // Not used anywhere /SAB
  260. _fIsWrite = FALSE;
  261. #endif
  262. _fDiscNoError = FALSE;
  263. _fNoDisconnectOnError = FALSE;
  264. SetState( HTR_READING_CLIENT_REQUEST );
  265. return TRUE;
  266. }
  267. VOID
  268. HTTP_REQ_BASE::SessionTerminated(
  269. VOID
  270. )
  271. /*++
  272. Routine Description:
  273. This method updates the statistics when the TCP session is closed just
  274. before this object gets destructed (or placed on the free list).
  275. Arguments:
  276. --*/
  277. {
  278. //
  279. // Notify filters
  280. //
  281. if ( _Filter.IsNotificationNeeded( SF_NOTIFY_END_OF_NET_SESSION,
  282. IsSecurePort() ))
  283. {
  284. _Filter.NotifyEndOfNetSession();
  285. }
  286. LPW3_SERVER_STATISTICS pStatsObj = QueryW3StatsObj();
  287. W3_STATISTICS_1 * pW3Stats = pStatsObj->QueryStatsObj();
  288. //
  289. // Update the statistics
  290. //
  291. if ( _fLoggedOn )
  292. {
  293. if ( _fAnonymous ) {
  294. pStatsObj->DecrCurrentAnonymousUsers();
  295. }
  296. else {
  297. pStatsObj->DecrCurrentNonAnonymousUsers();
  298. }
  299. }
  300. pStatsObj->LockStatistics();
  301. pW3Stats->TotalBytesSent.QuadPart += _cbTotalBytesSent + _cbBytesSent;
  302. pW3Stats->TotalBytesReceived.QuadPart += _cbTotalBytesReceived + _cbBytesReceived;
  303. pW3Stats->TotalFilesSent += _cFilesSent;
  304. pW3Stats->TotalFilesReceived += _cFilesReceived;
  305. pStatsObj->UnlockStatistics();
  306. TCP_REQUIRE( _tcpauth.Reset() );
  307. #if defined(CAL_ENABLED)
  308. if ( m_pCalSslCtxt )
  309. {
  310. CalDisconnect( m_pCalSslCtxt );
  311. m_pCalSslCtxt = NULL;
  312. }
  313. if ( m_pCalAuthCtxt )
  314. {
  315. CalDisconnect( m_pCalAuthCtxt );
  316. m_pCalAuthCtxt = NULL;
  317. }
  318. #endif
  319. //
  320. // Cleanup the filter
  321. //
  322. _Filter.Cleanup( );
  323. //
  324. // Make sure our input buffer doesn't grow too large. For example if
  325. // somebody just sent 500k of entity data, we want to release the memory
  326. // that was used to store that.
  327. //
  328. if ( _bufClientRequest.QuerySize() > MAX_CLIENT_SIZE_ALLOWED )
  329. {
  330. _bufClientRequest.FreeMemory();
  331. }
  332. }
  333. BOOL
  334. HTTP_REQ_BASE::OnIfModifiedSince(
  335. CHAR * pszValue
  336. )
  337. /*++
  338. Routine Description:
  339. Extracts the modified date for later use
  340. Arguments:
  341. pszValue - Pointer to zero terminated string
  342. --*/
  343. {
  344. if ( StringTimeToFileTime( pszValue,
  345. &_liModifiedSince ))
  346. {
  347. CHAR *pszLength;
  348. _fIfModifier = TRUE;
  349. pszLength = strchr(pszValue, ';');
  350. if (pszLength != NULL)
  351. {
  352. pszLength++;
  353. while (isspace((UCHAR)(*pszLength)))
  354. {
  355. pszLength++;
  356. }
  357. if (!_strnicmp(pszLength, "length", sizeof("length") - 1))
  358. {
  359. pszLength += sizeof("length") - 1;
  360. while (isspace((UCHAR)(*pszLength)))
  361. {
  362. pszLength++;
  363. }
  364. if (*pszLength == '=')
  365. {
  366. pszLength++;
  367. while (isspace((UCHAR)(*pszLength)))
  368. {
  369. pszLength++;
  370. }
  371. _dwModifiedSinceLength = atoi(pszLength);
  372. }
  373. }
  374. }
  375. return TRUE;
  376. }
  377. //
  378. // If we couldn't parse the time, then just ignore this field all
  379. // together
  380. //
  381. DBGPRINTF(( DBG_CONTEXT,
  382. "[OnIfModifiedSince] Error %d parsing If-Modified-Since time, ignoring field\n",
  383. GetLastError() ));
  384. _liModifiedSince.QuadPart = 0;
  385. _dwModifiedSinceLength = 0;
  386. return TRUE;
  387. }
  388. BOOL
  389. HTTP_REQ_BASE::OnIfUnmodifiedSince(
  390. CHAR * pszValue
  391. )
  392. /*++
  393. Routine Description:
  394. Extracts the unmodified date for later use
  395. Arguments:
  396. pszValue - Pointer to zero terminated string
  397. --*/
  398. {
  399. if ( StringTimeToFileTime( pszValue,
  400. &_liUnmodifiedSince ))
  401. {
  402. _fIfModifier = TRUE;
  403. return TRUE;
  404. }
  405. //
  406. // If we couldn't parse the time, then just ignore this field all
  407. // together
  408. //
  409. DBGPRINTF(( DBG_CONTEXT,
  410. "[OnIfUnmodifiedSince] Error %d parsing If-Modified-Since time, ignoring field\n",
  411. GetLastError() ));
  412. _liUnmodifiedSince.QuadPart = 0;
  413. return TRUE;
  414. }
  415. BOOL
  416. HTTP_REQ_BASE::OnUnlessModifiedSince(
  417. CHAR * pszValue
  418. )
  419. /*++
  420. Routine Description:
  421. Extracts the modified date for later use
  422. Arguments:
  423. pszValue - Pointer to zero terminated string
  424. --*/
  425. {
  426. BOOL fRet;
  427. if ( StringTimeToFileTime( pszValue,
  428. &_liUnlessModifiedSince ))
  429. {
  430. return TRUE;
  431. }
  432. //
  433. // If we couldn't parse the time, then just ignore this field all
  434. // together
  435. //
  436. DBGPRINTF(( DBG_CONTEXT,
  437. "[OnIfUnmodifiedSince] Error %d parsing If-Unmodified-Since time, ignoring field\n",
  438. GetLastError() ));
  439. _liUnlessModifiedSince.QuadPart = 0;
  440. return TRUE;
  441. }
  442. BOOL
  443. HTTP_REQ_BASE::OnIfMatch(
  444. CHAR * pszValue
  445. )
  446. /*++
  447. Routine Description:
  448. Handle the If-Match header.
  449. Arguments:
  450. pszValue - Pointer to zero terminated string
  451. --*/
  452. {
  453. _fIfModifier = TRUE;
  454. return TRUE;
  455. }
  456. BOOL
  457. HTTP_REQ_BASE::OnIfNoneMatch(
  458. CHAR * pszValue
  459. )
  460. /*++
  461. Routine Description:
  462. Handle the If-None-Match header.
  463. Arguments:
  464. pszValue - Pointer to zero terminated string
  465. --*/
  466. {
  467. _fIfModifier = TRUE;
  468. return TRUE;
  469. }
  470. BOOL
  471. HTTP_REQ_BASE::OnIfRange(
  472. CHAR * pszValue
  473. )
  474. /*++
  475. Routine Description:
  476. Handle the If-Range header.
  477. Arguments:
  478. pszValue - Pointer to zero terminated string
  479. --*/
  480. {
  481. _fIfModifier = TRUE;
  482. return TRUE;
  483. }
  484. /*******************************************************************
  485. NAME: HTTP_REQ_BASE::OnContentLength
  486. SYNOPSIS: Pulls out the number of bytes we expect the client to give us
  487. ENTRY: pszValue - Pointer to a zero terminated string
  488. RETURNS: TRUE if successful, FALSE if the field wasn't found
  489. HISTORY:
  490. Johnl 21-Sep-1994 Created
  491. ********************************************************************/
  492. BOOL HTTP_REQ_BASE::OnContentLength( CHAR * pszValue )
  493. {
  494. CHAR *pszEnd;
  495. if (!IsChunked())
  496. {
  497. // + and - aren't valid as part of a content length.
  498. if (*pszValue == '-' || *pszValue == '+')
  499. {
  500. SetLastError(ERROR_INVALID_PARAMETER);
  501. return FALSE;
  502. }
  503. errno = 0; // WinSE 16859
  504. _cbContentLength = strtoul( pszValue, &pszEnd, 10 );
  505. if (_cbContentLength == ULONG_MAX)
  506. {
  507. SetLastError(ERROR_INVALID_PARAMETER);
  508. return FALSE;
  509. }
  510. if (_cbContentLength == 0 || _cbContentLength == ULONG_MAX)
  511. {
  512. // Might possibly have underflow or overflow.
  513. if (errno == ERANGE || pszEnd == pszValue)
  514. {
  515. // Either had an overflow/underflow or no conversion.
  516. SetLastError(ERROR_INVALID_PARAMETER);
  517. return FALSE;
  518. }
  519. }
  520. // See what terminated the scan.
  521. if (*pszEnd != '\0' && !isspace((UCHAR)(*pszEnd)))
  522. {
  523. SetLastError(ERROR_INVALID_PARAMETER);
  524. return FALSE;
  525. }
  526. _fHaveContentLength = TRUE;
  527. }
  528. return TRUE;
  529. }
  530. BOOL
  531. HTTP_REQ_BASE::OnHost (
  532. CHAR * pszValue
  533. )
  534. /*++
  535. Routine Description:
  536. Processes the HTTP "Host: domain name" field
  537. Return Value:
  538. TRUE if successful, FALSE on error
  539. --*/
  540. {
  541. if ( !_strHostAddr.Copy( (TCHAR *) pszValue ) )
  542. {
  543. return FALSE;
  544. }
  545. //
  546. // remove erroneous port info if present
  547. // NYI: It will be very useful to get the length information
  548. //
  549. PSTR pP = (PSTR) memchr( _strHostAddr.QueryStr(), ':',
  550. _strHostAddr.QueryCB() );
  551. if ( pP != NULL )
  552. {
  553. *pP = '\0';
  554. _strHostAddr.SetLen( DIFF(pP - _strHostAddr.QueryStr()) );
  555. }
  556. return TRUE;
  557. }
  558. BOOL
  559. HTTP_REQ_BASE::OnRange (
  560. CHAR * pszValue
  561. )
  562. /*++
  563. Routine Description:
  564. Processes the HTTP "Range" field
  565. Return Value:
  566. TRUE if successful, FALSE on error
  567. --*/
  568. {
  569. while ( *pszValue && isspace((UCHAR)(*pszValue)) )
  570. ++pszValue;
  571. if ( !_strnicmp( pszValue, "bytes", sizeof("bytes")-1 ) )
  572. {
  573. pszValue += sizeof("bytes")-1;
  574. while ( *pszValue && *pszValue++ != '=' )
  575. ;
  576. while ( *pszValue && isspace((UCHAR)(*pszValue)) )
  577. ++pszValue;
  578. if ( !_strRange.Copy( (TCHAR *) pszValue ) )
  579. return FALSE;
  580. }
  581. return TRUE;
  582. }
  583. CHAR *
  584. HTTP_REQ_BASE::QueryHostAddr (
  585. VOID
  586. )
  587. /*++
  588. Routine Description:
  589. Returns the local domain name if specified in the request
  590. or else the local network address
  591. Return Value:
  592. ASCII representation of the local address
  593. --*/
  594. {
  595. if ( QueryW3Instance() == NULL )
  596. {
  597. return _pClientConn->QueryLocalAddr();
  598. }
  599. if ( IsProxyRequest() )
  600. {
  601. return ( QueryW3Instance()->QueryDefaultHostName() != NULL ?
  602. QueryW3Instance()->QueryDefaultHostName() :
  603. QueryClientConn()->QueryLocalAddr() );
  604. }
  605. else
  606. {
  607. return
  608. (CHAR *) (_strHostAddr.IsEmpty()
  609. ? ( (QueryW3Instance()->QueryDefaultHostName() != NULL)
  610. ? QueryW3Instance()->QueryDefaultHostName() : _pClientConn->QueryLocalAddr() )
  611. : _strHostAddr.QueryStr());
  612. }
  613. }
  614. #if 0
  615. Authorization info now processed after processing is complete
  616. BOOL
  617. HTTP_REQ_BASE::OnAuthorization(
  618. CHAR * pszValue
  619. )
  620. /*++
  621. Routine Description:
  622. Processes the HTTP "Authorization: <type> <authdata>" field
  623. Return Value:
  624. TRUE if successful, FALSE on error
  625. --*/
  626. {
  627. return TRUE;
  628. }
  629. #endif
  630. BOOL
  631. HTTP_REQ_BASE::ProcessAuthorization(
  632. CHAR * pszValue
  633. )
  634. /*++
  635. Routine Description:
  636. Processes the HTTP "Authorization: <type> <authdata>" field
  637. at logo time
  638. Return Value:
  639. TRUE if successful, FALSE on error
  640. --*/
  641. {
  642. //
  643. // If a filter has indicated this is a proxy request, use the
  644. // authorization information
  645. //
  646. if ( !IsProxyRequest() )
  647. {
  648. return ParseAuthorization( pszValue );
  649. }
  650. return TRUE;
  651. }
  652. BOOL
  653. HTTP_REQ_BASE::ParseAuthorization (
  654. CHAR * pszValue
  655. )
  656. /*++
  657. Routine Description:
  658. Processes the HTTP "Authorization: <type> <authdata>" field
  659. or "Proxy-Authorization: <type> <authdata>" field
  660. Return Value:
  661. TRUE if successful, FALSE on error
  662. --*/
  663. {
  664. CHAR * pchBlob;
  665. CHAR * pchSpace = NULL;
  666. DWORD dwAuthFlags = QueryAuthentication();
  667. //
  668. // If we've already logged this user and they're specifying authentication
  669. // headers, back out the old authentication information and
  670. // re-authenticate.
  671. //
  672. if ( IsLoggedOn() )
  673. {
  674. if ( !QueryW3Instance()->ProcessNtcrIfLoggedOn() )
  675. {
  676. //
  677. // Ignore the the authorization information if we're logged on with
  678. // an NT provider. Otherwise we authenticate every request with a
  679. // full challenge response
  680. //
  681. if ( !_fClearTextPass && !_fAnonymous )
  682. {
  683. goto NotFound;
  684. }
  685. }
  686. if ( _fAnonymous )
  687. {
  688. QueryW3StatsObj()->DecrCurrentAnonymousUsers();
  689. }
  690. else
  691. {
  692. QueryW3StatsObj()->DecrCurrentNonAnonymousUsers();
  693. }
  694. ResetAuth( FALSE );
  695. }
  696. //
  697. // If only anonymous is checked, ignore all authentication information
  698. // (i.e., force all users to the anonymous user).
  699. //
  700. if ( !(dwAuthFlags & (~INET_INFO_AUTH_ANONYMOUS) ))
  701. {
  702. goto NotFound;
  703. }
  704. //
  705. // Now break out the authorization type and see if it's an
  706. // authorization type we understand
  707. //
  708. pchSpace = pchBlob = strchr( pszValue, ' ' );
  709. if ( pchBlob )
  710. {
  711. *pchBlob = '\0';
  712. pchBlob++;
  713. }
  714. else
  715. {
  716. pchBlob = "";
  717. }
  718. if ( !_strAuthType.Copy( pszValue ) )
  719. {
  720. return FALSE;
  721. }
  722. //
  723. // This processes "user name:password"
  724. //
  725. if ( !_stricmp( _strAuthType.QueryStr(), "Basic" ) ||
  726. !_stricmp( _strAuthType.QueryStr(), "user" ))
  727. {
  728. //
  729. // If Basic is not enabled, force the user to anonymous if
  730. // anon is enabled or kick them out with Access denied
  731. //
  732. if ( !(dwAuthFlags & INET_INFO_AUTH_CLEARTEXT) )
  733. {
  734. if ( dwAuthFlags & INET_INFO_AUTH_ANONYMOUS )
  735. {
  736. _HeaderList.FastMapCancel( HM_AUT );
  737. _strAuthType.Reset();
  738. goto NotFound;
  739. }
  740. else
  741. {
  742. SetDeniedFlags( SF_DENIED_LOGON | SF_DENIED_BY_CONFIG );
  743. SetLastError( ERROR_ACCESS_DENIED );
  744. return FALSE;
  745. }
  746. }
  747. //
  748. // If the type is Basic, then the string has been uuencoded
  749. //
  750. if ( !ExtractClearNameAndPswd( pchBlob,
  751. &_strUserName,
  752. &_strPassword,
  753. *_strAuthType.QueryStr() == 'B' ||
  754. *_strAuthType.QueryStr() == 'b' ))
  755. {
  756. //
  757. // If we can't extract the username/pwd from Authorization header for
  758. // Basic, we'll assume the client sent an invalid blob
  759. //
  760. SetDeniedFlags( SF_DENIED_LOGON );
  761. SetLastError( ERROR_ACCESS_DENIED );
  762. return FALSE;
  763. }
  764. IF_DEBUG( PARSING )
  765. {
  766. DBGPRINTF(( DBG_CONTEXT,
  767. "[OnAuthorization] User name = %s\n",
  768. _strUserName.QueryStr(),
  769. _strPassword.QueryStr() ));
  770. }
  771. _fClearTextPass = TRUE;
  772. }
  773. else if ( !_stricmp( _strAuthType.QueryStr(), "Digest" ) ||
  774. !_stricmp( _strAuthType.QueryStr(), "NT-Digest" ) )
  775. {
  776. #if 0
  777. if ( !(QueryAuthentication()
  778. & INET_INFO_AUTH_MD5_AUTH) )
  779. {
  780. goto non_allowed;
  781. }
  782. LPSTR aValueTable[ MD5_AUTH_LAST ];
  783. STR strNonce;
  784. if ( !ParseForName( pchBlob,
  785. MD5_AUTH_NAMES,
  786. MD5_AUTH_LAST,
  787. aValueTable ) ||
  788. aValueTable[MD5_AUTH_USERNAME] == NULL ||
  789. aValueTable[MD5_AUTH_REALM] == NULL ||
  790. aValueTable[MD5_AUTH_URI] == NULL ||
  791. aValueTable[MD5_AUTH_NONCE] == NULL ||
  792. aValueTable[MD5_AUTH_RESPONSE] == NULL )
  793. {
  794. SetLastError( ERROR_INVALID_PARAMETER );
  795. return FALSE;
  796. }
  797. if ( GenerateNonce( &strNonce, IISSUBA_MD5 ) )
  798. {
  799. if ( _tcpauth.LogonDigestUser(
  800. aValueTable[MD5_AUTH_USERNAME],
  801. aValueTable[MD5_AUTH_REALM],
  802. aValueTable[MD5_AUTH_URI],
  803. _strMethod.QueryStr(),
  804. aValueTable[MD5_AUTH_NONCE],
  805. strNonce.QueryStr(),
  806. aValueTable[MD5_AUTH_RESPONSE],
  807. IISSUBA_MD5,
  808. g_pTsvcInfo ) )
  809. {
  810. _fAuthenticating = FALSE;
  811. _fLoggedOn = TRUE;
  812. }
  813. else
  814. {
  815. DWORD err = GetLastError();
  816. if ( err == ERROR_ACCESS_DENIED ||
  817. err == ERROR_LOGON_FAILURE )
  818. {
  819. _fAuthenticating = FALSE;
  820. SetDeniedFlags( SF_DENIED_LOGON );
  821. SetKeepConn( FALSE );
  822. }
  823. return FALSE;
  824. }
  825. }
  826. else
  827. {
  828. return FALSE;
  829. }
  830. #else
  831. _fAuthTypeDigest = TRUE;
  832. _strUserName.Reset();
  833. _strPassword.Copy ( pchBlob );
  834. #endif
  835. }
  836. else
  837. {
  838. //
  839. // See if it's one of the SSP packages
  840. //
  841. BUFFER buff;
  842. BOOL fNeedMoreData;
  843. DWORD cbOut;
  844. if ( !QueryMetaData()->CheckSSPPackage( _strAuthType.QueryStr() ) )
  845. {
  846. goto NotFound;
  847. }
  848. //
  849. // If NTLM is not enabled, force the user to anonymous if
  850. // anon is enabled or kick them out with Access denied
  851. //
  852. if ( !(dwAuthFlags & INET_INFO_AUTH_NT_AUTH) )
  853. {
  854. if ( dwAuthFlags & INET_INFO_AUTH_ANONYMOUS )
  855. {
  856. goto NotFound;
  857. }
  858. else
  859. {
  860. SetDeniedFlags( SF_DENIED_LOGON | SF_DENIED_BY_CONFIG );
  861. SetLastError( ERROR_ACCESS_DENIED );
  862. return FALSE;
  863. }
  864. }
  865. //
  866. // Process the authentication blob the client sent
  867. // us and build the blob to be returned in _strAuthInfo
  868. //
  869. if ( !_tcpauth.Converse( pchBlob,
  870. 0,
  871. &buff,
  872. &cbOut,
  873. &fNeedMoreData,
  874. QueryMetaData()->QueryAuthentInfo(),
  875. _strAuthType.QueryStr(),
  876. NULL,
  877. NULL,
  878. QueryW3Instance() ) ||
  879. !_strAuthInfo.Copy( _strAuthType ) ||
  880. !_strAuthInfo.Append( " ", 1 ) ||
  881. !_strAuthInfo.Append( cbOut ? ((CHAR *) buff.QueryPtr()) :
  882. "" ))
  883. {
  884. DWORD err = GetLastError();
  885. //
  886. // If the authentication package gives us a denied error, then
  887. // we need to reset our authorization info to indicate the client
  888. // needs to start from scratch. We also force a disconnect.
  889. //
  890. if ( err == ERROR_ACCESS_DENIED ||
  891. err == ERROR_LOGON_FAILURE )
  892. {
  893. _fAuthenticating = FALSE;
  894. SetDeniedFlags( SF_DENIED_LOGON );
  895. SetKeepConn( FALSE );
  896. }
  897. if ( err == ERROR_PASSWORD_EXPIRED ||
  898. err == ERROR_PASSWORD_MUST_CHANGE )
  899. {
  900. _fAuthenticating = FALSE;
  901. SetDeniedFlags( SF_DENIED_LOGON );
  902. SetKeepConn( FALSE );
  903. }
  904. return FALSE;
  905. }
  906. _fAuthenticating = fNeedMoreData;
  907. if ( !fNeedMoreData && !cbOut )
  908. {
  909. _strAuthInfo.Reset();
  910. }
  911. //
  912. // If the last server side conversation succeeded and there isn't
  913. // any more data, then we've successfully logged the user on
  914. //
  915. if ( _fLoggedOn = !fNeedMoreData )
  916. {
  917. if ( !CheckValidSSPILogin() )
  918. {
  919. return FALSE;
  920. }
  921. }
  922. #if 0
  923. else if ( !IsKeepConnSet() )
  924. {
  925. // no point in sending data : connection won't be kept alive
  926. // assume that auth method is session oriented
  927. SetDeniedFlags( SF_DENIED_LOGON );
  928. SetLastError( ERROR_ACCESS_DENIED );
  929. return FALSE;
  930. }
  931. #endif
  932. }
  933. NotFound:
  934. //
  935. // Restore the string
  936. //
  937. if ( pchSpace )
  938. {
  939. *pchSpace = ' ';
  940. }
  941. return TRUE;
  942. }
  943. BOOL
  944. HTTP_REQ_BASE::OnProxyAuthorization(
  945. CHAR * pszValue
  946. )
  947. /*++
  948. Routine Description:
  949. Processes the HTTP "Proxy-Authorization: <type> <authdata>" field
  950. Return Value:
  951. TRUE if successful, FALSE on error
  952. --*/
  953. {
  954. //
  955. // If a filter has indicated this is a proxy request, use the
  956. // authorization information
  957. //
  958. if ( IsProxyRequest() )
  959. {
  960. return ParseAuthorization( pszValue );
  961. }
  962. return TRUE;
  963. }
  964. /*******************************************************************
  965. NAME: HTTP_REQ_BASE::BuildStatusLine
  966. SYNOPSIS: Formulates the HTTP status line of the server response to
  967. the client of the form:
  968. <http version> <status code> <reason> <CrLf>
  969. ENTRY: pbufResp - Receives status string
  970. dwHTTPError - Response code to load
  971. dwError2 - Optional reason error
  972. NOTES: Optional acceptable authentication information will be
  973. added if the HTTP error is access denied
  974. HISTORY:
  975. Johnl 29-Aug-1994 Created
  976. ********************************************************************/
  977. BOOL HTTP_REQ_BASE::BuildStatusLine( BUFFER * pbufResp,
  978. DWORD dwHTTPError,
  979. DWORD dwError2,
  980. LPSTR pszError2,
  981. STR *pstrErrorStr)
  982. {
  983. STACK_STR( strStatus, MAX_PATH );
  984. STACK_STR( strError2, MAX_PATH );
  985. LPSTR pErr2 = NULL;
  986. LPSTR pFormatStrBuff = NULL;
  987. CHAR * pszStatus;
  988. CHAR ach[64];
  989. CHAR * pszTail;
  990. //
  991. // Get the HTTP error string
  992. //
  993. switch ( dwHTTPError )
  994. {
  995. case HT_OK:
  996. pszStatus = "OK";
  997. break;
  998. case HT_RANGE:
  999. pszStatus = "Partial content";
  1000. break;
  1001. case HT_NOT_MODIFIED:
  1002. pszStatus = "Not Modified";
  1003. break;
  1004. case HT_REDIRECT:
  1005. pszStatus = "Object Moved";
  1006. break;
  1007. default:
  1008. if ( !g_pInetSvc->LoadStr( strStatus, dwHTTPError + ID_HTTP_ERROR_BASE ))
  1009. {
  1010. DBGPRINTF((DBG_CONTEXT,
  1011. "BuildErrorResponse: failed to load HTTP status code %d (res=%d), error %d\n",
  1012. dwHTTPError,
  1013. dwHTTPError + ID_HTTP_ERROR_BASE,
  1014. GetLastError() ));
  1015. pszStatus = "Error";
  1016. }
  1017. else
  1018. {
  1019. pszStatus = strStatus.QueryStr();
  1020. }
  1021. break;
  1022. }
  1023. //
  1024. // If the client wants a secondary error string, get it now
  1025. //
  1026. if ( dwError2 )
  1027. {
  1028. if ( g_pInetSvc->LoadStr( strError2, dwError2 ))
  1029. {
  1030. pErr2 = strError2.QueryStr();
  1031. }
  1032. else
  1033. {
  1034. DBGPRINTF((DBG_CONTEXT,
  1035. "BuildErrorResponse: failed to load 2nd status code %d (res=%d), error %d\n",
  1036. dwError2,
  1037. dwError2,
  1038. GetLastError() ));
  1039. //
  1040. // Couldn't load the string, just provide the error number then
  1041. //
  1042. wsprintf( ach, "%d (0x%08lx)", dwError2, dwError2 );
  1043. if ( !strError2.Copy( ach ))
  1044. return FALSE;
  1045. pErr2 = strError2.QueryStr();
  1046. }
  1047. if ( dwError2 == ERROR_BAD_EXE_FORMAT )
  1048. {
  1049. // format the message to include file name
  1050. DWORD dwL = 0;
  1051. // handle exception that could be generated if this message
  1052. // requires more than the # of param we supply and AV
  1053. __try {
  1054. if ( !FormatMessage( ( FORMAT_MESSAGE_ALLOCATE_BUFFER|
  1055. FORMAT_MESSAGE_FROM_STRING|
  1056. FORMAT_MESSAGE_ARGUMENT_ARRAY
  1057. ),
  1058. strError2.QueryStr(),
  1059. 0,
  1060. 0,
  1061. (LPTSTR)&pFormatStrBuff,
  1062. dwL,
  1063. (va_list*)&pszError2 )
  1064. ) {
  1065. pErr2 = NULL;
  1066. pFormatStrBuff = NULL;
  1067. }
  1068. }
  1069. __except ( EXCEPTION_EXECUTE_HANDLER )
  1070. {
  1071. pErr2 = NULL;
  1072. pFormatStrBuff = NULL;
  1073. }
  1074. }
  1075. }
  1076. //
  1077. // Make sure there is room for the wsprintf
  1078. //
  1079. if ( !pbufResp->Resize( strlen(pszStatus) + 1 +
  1080. (pErr2 ? strlen(pErr2) : 0) +
  1081. LEN_PSZ_HTTP_VERSION_STR +
  1082. 20 * sizeof(TCHAR) )) // status code + space
  1083. {
  1084. if ( pFormatStrBuff )
  1085. LocalFree( pFormatStrBuff );
  1086. return FALSE;
  1087. }
  1088. pszTail = (CHAR *) pbufResp->QueryPtr();
  1089. //
  1090. // Build "HTTP/1.0 ### <status>\r\n" or "HTTP/1.0 ### <status> h(<Error>)\r\n"
  1091. //
  1092. if (!g_ReplyWith11)
  1093. {
  1094. APPEND_NUMERIC_HEADER( pszTail, "HTTP/1.0 ", dwHTTPError, " " );
  1095. }
  1096. else
  1097. {
  1098. APPEND_NUMERIC_HEADER( pszTail, "HTTP/1.1 ", dwHTTPError, " " );
  1099. }
  1100. APPEND_PSZ_HEADER( pszTail, "", pszStatus, "" );
  1101. if ( pErr2 )
  1102. {
  1103. if (pstrErrorStr != NULL)
  1104. {
  1105. if (!pstrErrorStr->Append(strError2))
  1106. {
  1107. pstrErrorStr->SetLen(0);
  1108. }
  1109. }
  1110. }
  1111. APPEND_STRING( pszTail, "\r\n" );
  1112. if ( pFormatStrBuff )
  1113. {
  1114. LocalFree( pFormatStrBuff );
  1115. }
  1116. return TRUE;
  1117. }
  1118. BOOL HTTP_REQ_BASE::BuildExtendedStatus(
  1119. STR * pstrResp,
  1120. DWORD dwHTTPError,
  1121. DWORD dwError2,
  1122. DWORD dwExplanation,
  1123. LPSTR pszError2
  1124. )
  1125. /*++
  1126. Routine Description:
  1127. This static method build a HTTP response string with extended explanation
  1128. information
  1129. Arguments:
  1130. pStr - Receives built response
  1131. dwHTTPError - HTTP error response
  1132. dwError2 - Extended error information (win/socket error)
  1133. dwExplanation - String ID of the explanation text
  1134. Return Value:
  1135. TRUE if successful, FALSE on error
  1136. --*/
  1137. {
  1138. // NYI: Who does the resize for the string before calling pstrResp ??
  1139. // How long is the buffer though ??
  1140. // The code originally assumed that there will be enough space
  1141. // to append strings after buildStatusLine -- we use assert to check it.
  1142. //
  1143. //
  1144. // "HTTP/<ver> <status>"
  1145. //
  1146. // NYI: Do a downlevel cast and send the buffer pointer around :(
  1147. if ( !BuildStatusLine( pstrResp,
  1148. dwHTTPError,
  1149. dwError2, pszError2))
  1150. {
  1151. return FALSE;
  1152. }
  1153. // NYI: I need to setlen here because the buffer object was used earlier.
  1154. DBG_REQUIRE( pstrResp->SetLen( strlen(pstrResp->QueryStr())));
  1155. //
  1156. // "Server: <Server>/<version>
  1157. // Obtain this fro the global cache.
  1158. //
  1159. DBG_REQUIRE( pstrResp->Append( szServerVersion,
  1160. (cbServerVersionString))
  1161. );
  1162. #if 0
  1163. //
  1164. // If we need to add an explanation, also include a content length
  1165. //
  1166. if ( dwExplanation )
  1167. {
  1168. STR str;
  1169. if ( !g_pInetSvc->LoadStr( str, dwExplanation ))
  1170. {
  1171. return FALSE;
  1172. }
  1173. DBG_REQUIRE( pstrResp->Append( str));
  1174. }
  1175. #endif
  1176. return TRUE;
  1177. }
  1178. BOOL
  1179. HTTP_REQ_BASE::LogonUser(
  1180. BOOL * pfFinished
  1181. )
  1182. /*++
  1183. Routine Description:
  1184. This method attempts to retrieve an impersonation token based
  1185. on the current request
  1186. Arguments:
  1187. pfFinished - Set to TRUE if no further processing is needed
  1188. Return Value:
  1189. TRUE if successful, FALSE on error
  1190. --*/
  1191. {
  1192. BOOL fAsGuest;
  1193. BOOL fAsAnonymous;
  1194. BOOL fAsync;
  1195. TCHAR * pszUser;
  1196. DWORD cbUser;
  1197. TCHAR * pszPswd;
  1198. DWORD cbPswd;
  1199. LPSTR pDns = NULL;
  1200. DWORD dwAuth;
  1201. HANDLE hAccessTokenPrimary = NULL;
  1202. HANDLE hAccessTokenImpersonation = NULL;
  1203. LPW3_SERVER_STATISTICS pStatsObj = QueryW3StatsObj();
  1204. W3_STATISTICS_1 * pW3Stats = pStatsObj->QueryStatsObj();
  1205. STACK_STR( strRealm, MAX_PATH); // make a local copy of the realm headers.
  1206. dwAuth = QueryAuthentication();
  1207. if ( _fAuthTypeDigest )
  1208. {
  1209. if ( dwAuth & INET_INFO_AUTH_MD5_AUTH )
  1210. {
  1211. if ( !_strUserName.Resize( SF_MAX_USERNAME ) ||
  1212. !_strUnmappedUserName.Resize( SF_MAX_USERNAME ) ||
  1213. !_strUnmappedUserName.Copy( _strUserName ) ||
  1214. !_strPassword.Resize( SF_MAX_PASSWORD ) ||
  1215. !_strUnmappedPassword.Copy( _strPassword ) ||
  1216. !_strAuthType.Resize(SF_MAX_AUTH_TYPE) )
  1217. {
  1218. return FALSE;
  1219. }
  1220. if ( _Filter.IsNotificationNeeded( SF_NOTIFY_AUTHENTICATIONEX,
  1221. IsSecurePort() ) &&
  1222. !_Filter.NotifyAuthInfoFiltersEx( _strUnmappedUserName.QueryStr(),
  1223. SF_MAX_USERNAME,
  1224. _strUserName.QueryStr(),
  1225. SF_MAX_USERNAME,
  1226. _strPassword.QueryStr(),
  1227. "",
  1228. QueryMetaData()->QueryAuthentInfo()->
  1229. strDefaultLogonDomain.QueryStr(),
  1230. _strAuthType.QueryStr(),
  1231. SF_MAX_AUTH_TYPE,
  1232. &hAccessTokenPrimary,
  1233. &hAccessTokenImpersonation,
  1234. pfFinished ))
  1235. {
  1236. SetDeniedFlags( SF_DENIED_LOGON | SF_DENIED_FILTER );
  1237. return FALSE;
  1238. }
  1239. //
  1240. // The filter may have modified the lengths - reset the lengths.
  1241. // Note _strPassword doesn't need to be reset here since
  1242. // NotifyAuthInfoFiltersEx() doesn't modify it.
  1243. //
  1244. _strUnmappedUserName.SetLen( strlen( _strUnmappedUserName.QueryStr()));
  1245. _strUserName.SetLen( strlen( _strUserName.QueryStr() ));
  1246. _strAuthType.SetLen( strlen( _strAuthType.QueryStr() ));
  1247. if ( *pfFinished )
  1248. {
  1249. return TRUE;
  1250. }
  1251. if ( hAccessTokenPrimary != NULL || hAccessTokenImpersonation != NULL )
  1252. {
  1253. _fMappedAcct = TRUE;
  1254. _fSingleRequestAuth = TRUE;
  1255. goto logged_in;
  1256. }
  1257. }
  1258. IF_DEBUG(ERROR) {
  1259. DBGPRINTF((DBG_CONTEXT,"Access denied based on configuration\n"));
  1260. }
  1261. SetDeniedFlags( SF_DENIED_LOGON | SF_DENIED_BY_CONFIG );
  1262. SetLastError( ERROR_ACCESS_DENIED );
  1263. return FALSE;
  1264. }
  1265. if ( !_strUnmappedUserName.Copy( _strUserName ) ||
  1266. !_strUnmappedPassword.Copy( _strPassword ))
  1267. {
  1268. return FALSE;
  1269. }
  1270. if ( _Filter.IsNotificationNeeded( SF_NOTIFY_AUTHENTICATION,
  1271. IsSecurePort() ))
  1272. {
  1273. if ( !_strUserName.Resize( SF_MAX_USERNAME ) ||
  1274. !_strPassword.Resize( SF_MAX_PASSWORD ) )
  1275. {
  1276. return FALSE;
  1277. }
  1278. if ( !_Filter.NotifyAuthInfoFilters( _strUserName.QueryStr(),
  1279. SF_MAX_USERNAME,
  1280. _strPassword.QueryStr(),
  1281. SF_MAX_PASSWORD,
  1282. pfFinished ))
  1283. {
  1284. IF_DEBUG(ERROR) {
  1285. DBGPRINTF((DBG_CONTEXT,"Access denied based on filter\n"));
  1286. }
  1287. SetDeniedFlags( SF_DENIED_LOGON | SF_DENIED_FILTER );
  1288. return FALSE;
  1289. }
  1290. _strUserName.SetLen( strlen( _strUserName.QueryStr() ));
  1291. _strPassword.SetLen( strlen( _strPassword.QueryStr() ));
  1292. if ( *pfFinished )
  1293. {
  1294. return TRUE;
  1295. }
  1296. if ( strcmp( _strUserName.QueryStr(),
  1297. _strUnmappedUserName.QueryStr() ) )
  1298. {
  1299. _fMappedAcct = TRUE;
  1300. }
  1301. }
  1302. if ( (dwAuth & INET_INFO_AUTH_MAPBASIC) &&
  1303. _Filter.IsNotificationNeeded( SF_NOTIFY_AUTHENTICATIONEX,
  1304. IsSecurePort() ) )
  1305. {
  1306. if ( !_strUserName.Resize( SF_MAX_USERNAME ) ||
  1307. !_strPassword.Resize( SF_MAX_PASSWORD ) ||
  1308. !_strAuthType.Resize( SF_MAX_AUTH_TYPE ) )
  1309. {
  1310. return FALSE;
  1311. }
  1312. //
  1313. // generate the realm information for this request
  1314. //
  1315. strRealm.Copy( QueryMetaData()->QueryRealm()
  1316. ? QueryMetaData()->QueryRealm()
  1317. : QueryHostAddr() );
  1318. if ( !_Filter.NotifyAuthInfoFiltersEx( _strUnmappedUserName.QueryStr(),
  1319. SF_MAX_USERNAME,
  1320. _strUserName.QueryStr(),
  1321. SF_MAX_USERNAME,
  1322. _strPassword.QueryStr(),
  1323. strRealm.QueryStr(),
  1324. QueryMetaData()->QueryAuthentInfo()->
  1325. strDefaultLogonDomain.QueryStr(),
  1326. _strAuthType.QueryStr(),
  1327. SF_MAX_AUTH_TYPE,
  1328. &hAccessTokenPrimary,
  1329. &hAccessTokenImpersonation,
  1330. pfFinished ))
  1331. {
  1332. IF_DEBUG(ERROR) {
  1333. DBGPRINTF((DBG_CONTEXT,"Access denied based on filter\n"));
  1334. }
  1335. SetDeniedFlags( SF_DENIED_LOGON | SF_DENIED_FILTER );
  1336. return FALSE;
  1337. }
  1338. _strUnmappedUserName.SetLen( strlen( _strUnmappedUserName.QueryStr()));
  1339. _strUserName.SetLen( strlen( _strUserName.QueryStr() ));
  1340. _strAuthType.SetLen( strlen( _strAuthType.QueryStr() ));
  1341. if ( *pfFinished )
  1342. {
  1343. return TRUE;
  1344. }
  1345. }
  1346. logged_in:
  1347. pszUser = *_strUserName.QueryStr() ?
  1348. _strUserName.QueryStr():
  1349. NULL;
  1350. cbUser = _strUserName.QueryCB();
  1351. pszPswd = *_strPassword.QueryStr() ?
  1352. _strPassword.QueryStr():
  1353. NULL;
  1354. cbPswd = _strPassword.QueryCB();
  1355. pStatsObj->IncrLogonAttempts();
  1356. logged_in2:
  1357. if ( (hAccessTokenPrimary != NULL) || (hAccessTokenImpersonation != NULL) )
  1358. {
  1359. _fMappedAcct = TRUE;
  1360. if ( !_tcpauth.SetAccessToken( hAccessTokenPrimary,
  1361. hAccessTokenImpersonation ))
  1362. {
  1363. DBGPRINTF(( DBG_CONTEXT,
  1364. "[ClearTextLogon] ::LogonUser failed, error %d\n",
  1365. GetLastError()));
  1366. return FALSE;
  1367. }
  1368. fAsGuest = FALSE;
  1369. fAsAnonymous = FALSE;
  1370. _fClearTextPass = FALSE;
  1371. }
  1372. else
  1373. {
  1374. if ( !(dwAuth & INET_INFO_AUTH_ANONYMOUS ) && (pszUser == NULL) )
  1375. {
  1376. IF_DEBUG(ERROR) {
  1377. DBGPRINTF((DBG_CONTEXT,
  1378. "Access denied based on configuration[%x]\n",
  1379. dwAuth));
  1380. }
  1381. SetDeniedFlags( SF_DENIED_LOGON | SF_DENIED_BY_CONFIG );
  1382. SetLastError( ERROR_ACCESS_DENIED );
  1383. return FALSE;
  1384. }
  1385. if ( QueryMetaData()->QueryAuthentInfo()->dwLogonMethod == LOGON32_LOGON_NETWORK )
  1386. {
  1387. switch ( QueryW3Instance()->QueryNetLogonWks() )
  1388. {
  1389. case MD_NETLOGON_WKS_DNS:
  1390. pDns = QueryClientConn()->QueryResolvedDnsName();
  1391. break;
  1392. case MD_NETLOGON_WKS_IP:
  1393. pDns = QueryClientConn()->QueryRemoteAddr();
  1394. break;
  1395. }
  1396. }
  1397. if ( ( cbUser > UNLEN ) || ( cbPswd > PWLEN ) )
  1398. {
  1399. SetDeniedFlags( SF_DENIED_LOGON );
  1400. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  1401. return FALSE;
  1402. }
  1403. if ( !_tcpauth.ClearTextLogon( pszUser,
  1404. pszPswd,
  1405. &fAsGuest,
  1406. &fAsAnonymous,
  1407. QueryW3Instance(),
  1408. QueryMetaData()->QueryAuthentInfo(),
  1409. pDns ))
  1410. {
  1411. DBGPRINTF(( DBG_CONTEXT,
  1412. "[ClearTextLogon] ::LogonUser failed, error %d\n",
  1413. GetLastError()));
  1414. DWORD dwErr = GetLastError();
  1415. if ( (fAsAnonymous || fAsGuest) &&
  1416. (dwErr == ERROR_LOGIN_TIME_RESTRICTION ||
  1417. dwErr == ERROR_INVALID_LOGON_HOURS ||
  1418. dwErr == ERROR_ACCOUNT_DISABLED ||
  1419. dwErr == ERROR_ACCOUNT_LOCKED_OUT ||
  1420. dwErr == ERROR_ACCOUNT_EXPIRED ) )
  1421. {
  1422. dwErr = ERROR_ACCESS_DENIED;
  1423. }
  1424. //
  1425. // If we pass an invalid username/domain to LogonUser, LastError is set
  1426. // to ERROR_INVALID_PARAMETER, so we'll just massage that into returning
  1427. // "Access Denied"
  1428. //
  1429. if ( (dwErr == ERROR_ACCESS_DENIED) ||
  1430. (dwErr == ERROR_LOGON_FAILURE) ||
  1431. (dwErr == ERROR_INVALID_PARAMETER) )
  1432. {
  1433. SetDeniedFlags( SF_DENIED_LOGON );
  1434. dwErr = ERROR_ACCESS_DENIED;
  1435. }
  1436. //
  1437. // Query fully qualified name ( including domain )
  1438. // so that we can prompt user for new password
  1439. // with a name suitable for NetUserChangePassword
  1440. //
  1441. _tcpauth.QueryFullyQualifiedUserName( pszUser,
  1442. &_strUnmappedUserName,
  1443. QueryW3Instance(),
  1444. QueryMetaData()->QueryAuthentInfo());
  1445. //
  1446. // set last error here because QueryFullyQualifiedUserName
  1447. // modified last error.
  1448. //
  1449. SetLastError( dwErr );
  1450. return FALSE;
  1451. }
  1452. }
  1453. //
  1454. // Are anonymous or clear text (basic) logons allowed? We assume
  1455. // it's an NT logon if it's neither one of these
  1456. //
  1457. if ( fAsAnonymous &&
  1458. !(dwAuth & INET_INFO_AUTH_ANONYMOUS ))
  1459. {
  1460. DBGPRINTF(( DBG_CONTEXT,
  1461. "[ClearTextLogon] Denying anonymous logon (not enabled), user %s\n",
  1462. _strUserName.QueryStr() ));
  1463. SetDeniedFlags( SF_DENIED_LOGON | SF_DENIED_BY_CONFIG );
  1464. SetLastError( ERROR_ACCESS_DENIED );
  1465. return FALSE;
  1466. }
  1467. else if ( _fClearTextPass &&
  1468. !(dwAuth & INET_INFO_AUTH_CLEARTEXT ))
  1469. {
  1470. DBGPRINTF(( DBG_CONTEXT,
  1471. "[ClearTextLogon] Denying clear text logon (not enabled), user %s\n",
  1472. _strUserName.QueryStr() ));
  1473. SetDeniedFlags( SF_DENIED_LOGON | SF_DENIED_BY_CONFIG );
  1474. SetLastError( ERROR_ACCESS_DENIED );
  1475. return FALSE;
  1476. }
  1477. if ( fAsGuest )
  1478. {
  1479. if ( !(dwAuth & INET_INFO_AUTH_ANONYMOUS ) )
  1480. {
  1481. DBGPRINTF(( DBG_CONTEXT,
  1482. "[ClearTextLogon] Denying guest logon (not enabled), user %s\n",
  1483. _strUserName.QueryStr() ));
  1484. SetDeniedFlags( SF_DENIED_LOGON | SF_DENIED_BY_CONFIG );
  1485. SetLastError( ERROR_ACCESS_DENIED );
  1486. return FALSE;
  1487. }
  1488. if ( !fAsAnonymous )
  1489. {
  1490. _tcpauth.Reset();
  1491. _strUserName.Reset();
  1492. _strPassword.Reset();
  1493. pszUser = NULL;
  1494. pszPswd = NULL;
  1495. cbUser = 0;
  1496. cbPswd = 0;
  1497. goto logged_in2;
  1498. }
  1499. }
  1500. _fLoggedOn = TRUE;
  1501. _fAnonymous = fAsAnonymous;
  1502. if ( fAsAnonymous )
  1503. {
  1504. pStatsObj->IncrAnonymousUsers();
  1505. _cbLastAnonAcctDesc = QueryMetaData()->QueryAuthentInfo()->cbAnonAcctDesc;
  1506. if (!_bufLastAnonAcctDesc.Resize(_cbLastAnonAcctDesc) )
  1507. {
  1508. // Couldn't resize the buffer properly, set the size to 0 so
  1509. // we'll force a relogon each time to be safe.
  1510. _cbLastAnonAcctDesc = 0;
  1511. }
  1512. memcpy(_bufLastAnonAcctDesc.QueryPtr(),
  1513. QueryMetaData()->QueryAuthentInfo()->bAnonAcctDesc.QueryPtr(),
  1514. _cbLastAnonAcctDesc);
  1515. }
  1516. else
  1517. {
  1518. pStatsObj->IncrNonAnonymousUsers();
  1519. _cbLastAnonAcctDesc = 0;
  1520. }
  1521. return TRUE;
  1522. }
  1523. # define MAX_ERROR_MESSAGE_LEN ( 500)
  1524. #define EXTRA_LOGGING_BUFFER_SIZE 2048
  1525. BOOL
  1526. HTTP_REQ_BASE::WriteLogRecord(
  1527. VOID
  1528. )
  1529. /*++
  1530. Routine Description:
  1531. Writes a transaction log for this request
  1532. Return Value:
  1533. TRUE if successful, FALSE on error
  1534. --*/
  1535. {
  1536. //
  1537. // HACK ALERT
  1538. //
  1539. // This function may crash if this request has already written
  1540. // a log record - bail out now if so.
  1541. //
  1542. // This HACK must precede the call to EndOfRequest(), which
  1543. // is the likely cause of the crash.
  1544. //
  1545. // NOTE we set flag true immediately (even though we still may
  1546. // not log) to absolutely guarantee that we won't hit the crash,
  1547. // and to keep code for this hack as localized as possible.
  1548. //
  1549. // CONSIDER for AFTER we ship IIS 4.0:
  1550. // clean up cause of crash, and then remove this hack
  1551. //
  1552. if ( _fLogRecordWritten )
  1553. {
  1554. return TRUE;
  1555. }
  1556. _fLogRecordWritten = TRUE;
  1557. INETLOG_INFORMATION ilRequest;
  1558. HTTP_FILTER_LOG Log;
  1559. DWORD dwLog;
  1560. BOOL fDontLog = FALSE;
  1561. LPSTR pszClientHostName = QueryClientConn()->QueryRemoteAddr();
  1562. //
  1563. // Metadata pointer can be NULL at this point
  1564. //
  1565. if ( QueryMetaData() )
  1566. {
  1567. if ( QueryMetaData()->QueryDoReverseDns() &&
  1568. QueryClientConn()->IsDnsResolved() )
  1569. {
  1570. pszClientHostName = QueryClientConn()->QueryResolvedDnsName();
  1571. }
  1572. fDontLog = QueryMetaData()->DontLog();
  1573. }
  1574. //
  1575. // Notify filters and close any handles for this request
  1576. //
  1577. EndOfRequest();
  1578. //
  1579. // Log this request if we actually did anything
  1580. //
  1581. if ( _dwLogHttpResponse == HT_DONT_LOG || IsProxyRequest() )
  1582. {
  1583. if ( !IsProxyRequest() )
  1584. {
  1585. IF_DEBUG(REQUEST) {
  1586. DBGPRINTF(( DBG_CONTEXT,
  1587. "[WriteLogRecord] not writing log record, status is HT_DONT_LOG\n" ));
  1588. }
  1589. }
  1590. return TRUE;
  1591. }
  1592. //
  1593. // If no logging is required, get out now
  1594. //
  1595. if ( ((HTTP_REQUEST*)this)->QueryVerb() == HTV_TRACECK ||
  1596. (QueryW3Instance() == NULL) ||
  1597. (!QueryW3Instance()->IsLoggingEnabled()) ||
  1598. (!QueryW3Instance()->IsLogErrors() && (QueryLogWinError() || (QueryLogHttpResponse() >= 400))) ||
  1599. (!QueryW3Instance()->IsLogSuccess() && (QueryLogWinError() == NO_ERROR) &&
  1600. (QueryLogHttpResponse() < 400)) ||
  1601. fDontLog )
  1602. {
  1603. return TRUE;
  1604. }
  1605. if ( _Filter.IsNotificationNeeded( SF_NOTIFY_LOG,
  1606. IsSecurePort() ))
  1607. {
  1608. //
  1609. // If we have filters, use the possible filter replacement items
  1610. //
  1611. Log.pszClientHostName = pszClientHostName;
  1612. Log.pszClientUserName = _strUserName.QueryStr();
  1613. Log.pszServerName = QueryClientConn()->QueryLocalAddr();
  1614. Log.pszOperation = _strMethod.QueryStr();
  1615. Log.pszTarget = _strURL.QueryStr();
  1616. Log.pszParameters = _strLogParams.QueryCCH() ?
  1617. _strLogParams.QueryStr() :
  1618. _strURLParams.QueryStr();
  1619. Log.dwHttpStatus = QueryLogHttpResponse();
  1620. Log.dwWin32Status = QueryLogWinError();
  1621. Log.dwBytesSent = _cbBytesSent;
  1622. Log.dwBytesRecvd = _cbClientRequest + _cbTotalEntityBody;
  1623. Log.msTimeForProcessing = GetCurrentTime() - _msStartRequest;
  1624. _Filter.NotifyLogFilters( &Log );
  1625. ilRequest.pszClientHostName = (char *) Log.pszClientHostName;
  1626. ilRequest.pszClientUserName = (char *) Log.pszClientUserName;
  1627. ilRequest.pszServerAddress = (char *) Log.pszServerName;
  1628. ilRequest.pszOperation = (char *) Log.pszOperation;
  1629. ilRequest.pszTarget = (char *) Log.pszTarget;
  1630. ilRequest.pszParameters = (char *) Log.pszParameters;
  1631. ilRequest.dwProtocolStatus = Log.dwHttpStatus;
  1632. ilRequest.dwWin32Status = Log.dwWin32Status;
  1633. ilRequest.msTimeForProcessing = Log.msTimeForProcessing;
  1634. ilRequest.dwBytesSent = Log.dwBytesSent;
  1635. ilRequest.dwBytesRecvd = Log.dwBytesRecvd;
  1636. ilRequest.cbOperation = strlen( Log.pszOperation );
  1637. ilRequest.cbTarget = strlen( Log.pszTarget );
  1638. ilRequest.cbClientHostName = strlen(ilRequest.pszClientHostName);
  1639. }
  1640. else
  1641. {
  1642. ilRequest.pszClientHostName = pszClientHostName;
  1643. ilRequest.pszClientUserName = _strUserName.QueryStr();
  1644. ilRequest.pszServerAddress = QueryClientConn()->QueryLocalAddr();
  1645. ilRequest.pszOperation = _strMethod.QueryStr();
  1646. ilRequest.pszTarget = _strURL.QueryStr();
  1647. ilRequest.pszParameters = _strLogParams.QueryCCH() ?
  1648. _strLogParams.QueryStr() :
  1649. _strURLParams.QueryStr();
  1650. ilRequest.dwProtocolStatus = QueryLogHttpResponse();
  1651. ilRequest.dwWin32Status = QueryLogWinError();
  1652. ilRequest.msTimeForProcessing = GetCurrentTime() - _msStartRequest;
  1653. ilRequest.dwBytesSent = _cbBytesSent;
  1654. ilRequest.dwBytesRecvd = _cbClientRequest + _cbTotalEntityBody;
  1655. //
  1656. // Get length of some strings
  1657. //
  1658. ilRequest.cbOperation = _strMethod.QueryCCH();
  1659. ilRequest.cbTarget = _strURL.QueryCCH();
  1660. ilRequest.cbClientHostName = strlen(ilRequest.pszClientHostName);
  1661. }
  1662. //
  1663. // write capacity planning trace info.
  1664. //
  1665. if (GetIISCapTraceFlag())
  1666. {
  1667. PIIS_CAP_TRACE_INFO pHttpCapTraceInfo;
  1668. pHttpCapTraceInfo = AtqGetCapTraceInfo(QueryClientConn()->QueryAtqContext());
  1669. pHttpCapTraceInfo->IISCapTraceHeader.TraceHeader.Size = sizeof (IIS_CAP_TRACE_INFO);
  1670. pHttpCapTraceInfo->IISCapTraceHeader.TraceHeader.Class.Type = EVENT_TRACE_TYPE_INFO;
  1671. pHttpCapTraceInfo->MofFields[0].Length = ilRequest.cbOperation+1;
  1672. pHttpCapTraceInfo->MofFields[0].DataPtr = (ULONGLONG) ilRequest.pszOperation;
  1673. pHttpCapTraceInfo->MofFields[1].Length = ilRequest.cbTarget+1;
  1674. pHttpCapTraceInfo->MofFields[1].DataPtr = (ULONGLONG) ilRequest.pszTarget;
  1675. pHttpCapTraceInfo->MofFields[2].Length = sizeof(DWORD);
  1676. pHttpCapTraceInfo->MofFields[2].DataPtr = (ULONGLONG) &ilRequest.dwBytesSent;
  1677. if ( ERROR_INVALID_HANDLE == TraceEvent ( GetIISCapTraceLoggerHandle(),
  1678. (PEVENT_TRACE_HEADER) pHttpCapTraceInfo))
  1679. {
  1680. SetIISCapTraceFlag(0);
  1681. }
  1682. }
  1683. BYTE pchTemp[EXTRA_LOGGING_BUFFER_SIZE];
  1684. BUFFER buf( pchTemp, EXTRA_LOGGING_BUFFER_SIZE); // init w/- stack buffer
  1685. ilRequest.pszHTTPHeader= NULL;
  1686. ilRequest.dwPort = QueryClientConn()->QueryPort( );
  1687. ilRequest.pszVersion=(LPSTR)_HeaderList.FastMapQueryValue(HM_VER);
  1688. //
  1689. // Only log extra fields if the request was from a version > 0.9 [which didn't
  1690. // have headers] and extra logging fields have been requested
  1691. //
  1692. if ( !IsPointNine() &&
  1693. QueryW3Instance()->m_Logging.IsRequiredExtraLoggingFields())
  1694. {
  1695. //
  1696. // reconstruct the buffer
  1697. //
  1698. PCHAR pszFieldName =
  1699. QueryW3Instance()->m_Logging.QueryExtraLoggingFields();
  1700. DWORD cbValueSize=0;
  1701. DWORD cbTotalSize=0;
  1702. DWORD cbActualSize=0;
  1703. DWORD cbCurrentBufferSize = EXTRA_LOGGING_BUFFER_SIZE;
  1704. PCHAR pszValue;
  1705. PCHAR pszBuff = (TCHAR *) buf.QueryPtr();
  1706. while ( *pszFieldName != '\0' )
  1707. {
  1708. //
  1709. // add the string into the buffer
  1710. //
  1711. pszValue = QueryHeaderList()->FindValue(
  1712. pszFieldName,
  1713. &cbValueSize
  1714. );
  1715. if ( pszValue == NULL ) {
  1716. cbValueSize = 0;
  1717. pszValue = "";
  1718. }
  1719. cbTotalSize = cbActualSize + cbValueSize + 2;
  1720. if (cbTotalSize > cbCurrentBufferSize)
  1721. {
  1722. buf.Resize(cbTotalSize);
  1723. cbCurrentBufferSize = cbTotalSize;
  1724. pszBuff=(TCHAR*)buf.QueryPtr();
  1725. pszBuff += cbActualSize;
  1726. }
  1727. CopyMemory( pszBuff, pszValue, strlen(pszValue)+1);
  1728. pszFieldName += strlen(pszFieldName) + 1;
  1729. pszBuff += cbValueSize+1;
  1730. cbActualSize += cbValueSize+1;
  1731. *pszBuff = '\0';
  1732. }
  1733. ilRequest.pszHTTPHeader = (PCHAR)buf.QueryPtr();
  1734. ilRequest.cbHTTPHeaderSize = cbActualSize;
  1735. }
  1736. dwLog = QueryW3Instance()->m_Logging.LogInformation(&ilRequest);
  1737. if ( dwLog != NO_ERROR )
  1738. {
  1739. DBGPRINTF((DBG_CONTEXT,
  1740. "[WriteLogRecord] - Failed, error %d\n",
  1741. GetLastError() ));
  1742. //
  1743. // We should make sure LogInformation will never fail
  1744. //
  1745. }
  1746. return TRUE;
  1747. }
  1748. BOOL
  1749. HTTP_REQ_BASE::AppendLogParameter(
  1750. CHAR * pszParam
  1751. )
  1752. /*++
  1753. Routine Description:
  1754. Appends data for logging.
  1755. Arguments:
  1756. pszParam - The data to be appended
  1757. Return Value:
  1758. TRUE if successful, FALSE on error
  1759. Notes:
  1760. The way that AppendLogData works is that it just appends
  1761. data to the query string, so that when the query string
  1762. is logged, the new data gets a free ride.
  1763. The problem with this is that anyone who looks at the
  1764. query string after AppendLogParameter will see the additional
  1765. log data.
  1766. To prevent this, we'll create a copy of the query string
  1767. data upon the first call of this function and then append
  1768. the new data to the copy. When the log is written, the copy
  1769. will be written if it has data, else the original query
  1770. string will be written.
  1771. --*/
  1772. {
  1773. //
  1774. // If the _strLogParams buffer is empty, copy
  1775. // the query string first.
  1776. //
  1777. if ( _strLogParams.QueryCCH() == 0 )
  1778. {
  1779. BOOL fRet = _strLogParams.Copy( _strURLParams.QueryStr() );
  1780. if ( !fRet )
  1781. {
  1782. return fRet;
  1783. }
  1784. }
  1785. //
  1786. // Append the new data.
  1787. //
  1788. return _strLogParams.Append( pszParam );
  1789. }
  1790. BOOL
  1791. HTTP_REQ_BASE::BuildHttpHeader( OUT BOOL * pfFinished,
  1792. IN CHAR * pchStatus OPTIONAL,
  1793. IN CHAR * pchAdditionalHeaders OPTIONAL,
  1794. IN DWORD dwOptions)
  1795. /*++
  1796. Routine Description:
  1797. Builds a full HTTP header reply with an optional status and
  1798. other headers/data
  1799. Arguments:
  1800. pchStatus - optional HTTP status string like "401 Access Denied"
  1801. pchAdditionalHeaders - optional additional HTTP or MIME headers and
  1802. data. Must supply own '\r\n' terminator if this parameter is
  1803. supplied
  1804. pfFinished - Set to TRUE if no further processing is required
  1805. Return Value:
  1806. TRUE on success, FALSE on failure
  1807. --*/
  1808. {
  1809. STR str;
  1810. BOOL fFinished = FALSE;
  1811. if ( pchStatus )
  1812. {
  1813. DWORD cbLen = ::strlen( pchStatus);
  1814. // NYI: Can we compress the calls to string class here
  1815. // Also make sure enough space is allocated in string object
  1816. if ( !str.Resize( LEN_PSZ_HTTP_VERSION_STR + cbLen + 4) ||
  1817. !str.Copy( (!g_ReplyWith11 ? PSZ_HTTP_VERSION_STR :
  1818. PSZ_HTTP_VERSION_STR11),
  1819. LEN_PSZ_HTTP_VERSION_STR ) ||
  1820. !str.Append( pchStatus, cbLen )
  1821. )
  1822. {
  1823. return FALSE;
  1824. }
  1825. // I am safe to assume space is there, because of resize
  1826. DBG_ASSERT( str.QueryCB() < (str.QuerySize() - 2));
  1827. str.AppendCRLF();
  1828. }
  1829. if ( !BuildBaseResponseHeader( QueryRespBuf(),
  1830. pfFinished,
  1831. (pchStatus ? &str : NULL ),
  1832. dwOptions ))
  1833. {
  1834. return FALSE;
  1835. }
  1836. if ( pchAdditionalHeaders )
  1837. {
  1838. DWORD dwAddlHdrLength;
  1839. DWORD dwCurrentLength;
  1840. dwAddlHdrLength = strlen(pchAdditionalHeaders) + 1;
  1841. dwCurrentLength = QueryRespBufCB();
  1842. if (!QueryRespBuf()->Resize(dwCurrentLength + dwAddlHdrLength))
  1843. {
  1844. return FALSE;
  1845. }
  1846. memcpy(QueryRespBufPtr() + dwCurrentLength,
  1847. pchAdditionalHeaders,
  1848. dwAddlHdrLength);
  1849. }
  1850. return TRUE;
  1851. } // HTTP_REQ_BASE::BuildHttpHeader()
  1852. BOOL
  1853. HTTP_REQ_BASE::SendHeader(
  1854. IN CHAR * pchStatus OPTIONAL,
  1855. IN CHAR * pchAdditionalHeaders OPTIONAL,
  1856. IN DWORD IOFlags,
  1857. OUT BOOL * pfFinished,
  1858. IN DWORD dwOptions,
  1859. IN BOOL fWriteHeader
  1860. )
  1861. /*++
  1862. Routine Description:
  1863. Does a synchronous send of an HTTP header with optional status
  1864. and additional headers.
  1865. Arguments:
  1866. pchStatus - HTTP Status code (or NULL for "200 Ok")
  1867. pchAdditionalHeaders - Headers to add to the standard response set
  1868. IOFlags - IO_* flags to send the headers with
  1869. pfFinished - Set to TRUE if no further processing is needed for this
  1870. request
  1871. fWriteHeader - Defaults to TRUE; pass FALSE to suppress writing headers
  1872. (designed for callers that want to send header and body together)
  1873. Return Value:
  1874. TRUE on success, FALSE on failure
  1875. --*/
  1876. {
  1877. DWORD BytesSent;
  1878. DWORD cbAddHeaders;
  1879. BOOL fAnyChanges = FALSE;
  1880. *pfFinished = FALSE;
  1881. if ( pchAdditionalHeaders )
  1882. {
  1883. cbAddHeaders = strlen( pchAdditionalHeaders );
  1884. if ( cbAddHeaders &&
  1885. cbAddHeaders > QueryRespBuf()->QuerySize() / 2)
  1886. {
  1887. if ( !QueryRespBuf()->Resize( QueryRespBuf()->QuerySize() +
  1888. cbAddHeaders ))
  1889. {
  1890. return FALSE;
  1891. }
  1892. }
  1893. }
  1894. if ( !BuildHttpHeader( pfFinished,
  1895. pchStatus,
  1896. pchAdditionalHeaders,
  1897. dwOptions))
  1898. {
  1899. return FALSE;
  1900. }
  1901. if ( *pfFinished )
  1902. {
  1903. return TRUE;
  1904. }
  1905. DBG_ASSERT( QueryRespBufCB() <=
  1906. QueryRespBuf()->QuerySize() );
  1907. if ( _Filter.IsNotificationNeeded( SF_NOTIFY_SEND_RESPONSE,
  1908. IsSecurePort() ))
  1909. {
  1910. if ( !_Filter.NotifySendHeaders( QueryRespBufPtr(),
  1911. pfFinished,
  1912. &fAnyChanges,
  1913. QueryRespBuf() ))
  1914. {
  1915. return FALSE;
  1916. }
  1917. if ( *pfFinished )
  1918. {
  1919. return TRUE;
  1920. }
  1921. }
  1922. if ( fWriteHeader )
  1923. {
  1924. if ( !WriteFile( QueryRespBufPtr(),
  1925. QueryRespBufCB(),
  1926. &BytesSent,
  1927. IOFlags ))
  1928. {
  1929. return FALSE;
  1930. }
  1931. }
  1932. return TRUE;
  1933. } // HTTP_REQ_BASE::SendHeader()
  1934. BOOL
  1935. HTTP_REQ_BASE::SendHeader(
  1936. IN CHAR * pchHeaders,
  1937. IN DWORD cbHeaders,
  1938. IN DWORD IOFlags,
  1939. OUT BOOL * pfFinished
  1940. )
  1941. /*++
  1942. Routine Description:
  1943. Does a send of the HTTP header response where the status is already
  1944. embedded in the header set
  1945. If the pfFinished comes back TRUE and IO_FLAG_ASYNC was specified, then
  1946. an IO completion will be made
  1947. Arguments:
  1948. pchHeaders - Pointer to header set
  1949. cbHeaders - Length of headers to send (or -1 if headers are '\0' terminated)
  1950. IOFlags - IO_* flags to send the headers with
  1951. pfFinished - Set to TRUE if no further processing is needed for this
  1952. request
  1953. Return Value:
  1954. TRUE on success, FALSE on failure
  1955. --*/
  1956. {
  1957. DWORD BytesSent;
  1958. DWORD cbAddHeaders;
  1959. BOOL fAnyChanges = FALSE;
  1960. *pfFinished = FALSE;
  1961. if ( _Filter.IsNotificationNeeded( SF_NOTIFY_SEND_RESPONSE,
  1962. IsSecurePort() ))
  1963. {
  1964. if ( !_Filter.NotifySendHeaders( pchHeaders,
  1965. pfFinished,
  1966. &fAnyChanges,
  1967. QueryRespBuf() ))
  1968. {
  1969. return FALSE;
  1970. }
  1971. if ( *pfFinished )
  1972. {
  1973. return TRUE;
  1974. }
  1975. if ( fAnyChanges )
  1976. {
  1977. pchHeaders = QueryRespBufPtr();
  1978. cbHeaders = QueryRespBufCB();
  1979. }
  1980. }
  1981. if ( cbHeaders == -1 )
  1982. {
  1983. cbHeaders = strlen( pchHeaders );
  1984. }
  1985. if ( !WriteFile( pchHeaders,
  1986. cbHeaders,
  1987. &BytesSent,
  1988. IOFlags ))
  1989. {
  1990. return FALSE;
  1991. }
  1992. return TRUE;
  1993. } // HTTP_REQ_BASE::SendHeader()
  1994. #define NO_CACHE_HEADER_SIZE (sizeof("Cache-Control: no-cache,no-transform\r\n") - 1 +\
  1995. sizeof("Expires: Mon, 00 Jan 0000 00:00:00 GMT\r\n") - 1)
  1996. BOOL
  1997. HTTP_REQ_BASE::BuildBaseResponseHeader(
  1998. BUFFER * pbufResponse,
  1999. BOOL * pfFinished,
  2000. STR * pstrStatus,
  2001. DWORD dwOptions
  2002. )
  2003. /*++
  2004. Routine Description:
  2005. Builds a set of common server response headers
  2006. Arguments:
  2007. pbufResponse - Receives response headers
  2008. pfFinished - Set to TRUE if no further processing is needed
  2009. pstrStatus - Optional HTTP response status (defaults to 200)
  2010. dwOptions - bit field of options.
  2011. HTTPH_SEND_GLOBAL_EXPIRE Indicates whether an
  2012. "Expires: xxx" based on the global expires value
  2013. is include with the headers
  2014. HTTPH_NO_DATE indicates whether to generate a
  2015. "Date:" header.
  2016. Return Value:
  2017. TRUE on success, FALSE on failure
  2018. --*/
  2019. {
  2020. FILETIME ftSysTime;
  2021. CHAR achTime[64];
  2022. BOOL fSysTimeValid = FALSE;
  2023. CHAR * pszResp;
  2024. CHAR * pszTail;
  2025. DWORD cb;
  2026. DWORD cbExpire;
  2027. DWORD cbCustom;
  2028. DWORD cbLeft;
  2029. DWORD dwSizeUsed;
  2030. pszResp = (CHAR *) pbufResponse->QueryPtr();
  2031. //
  2032. // Add the status line - "HTTP/1.0 nnn sss...\r\n"
  2033. //
  2034. if ( !pstrStatus )
  2035. {
  2036. pszTail = pszResp;
  2037. if ( !_fProcessByteRange )
  2038. {
  2039. if (!g_ReplyWith11)
  2040. {
  2041. APPEND_STRING( pszTail, "HTTP/1.0 200 OK\r\n" );
  2042. }
  2043. else
  2044. {
  2045. APPEND_STRING( pszTail, "HTTP/1.1 200 OK\r\n" );
  2046. }
  2047. } else
  2048. {
  2049. if (!g_ReplyWith11)
  2050. {
  2051. APPEND_STRING( pszTail, "HTTP/1.0 206 Partial content\r\n" );
  2052. }
  2053. else
  2054. {
  2055. APPEND_STRING( pszTail, "HTTP/1.1 206 Partial content\r\n" );
  2056. }
  2057. }
  2058. }
  2059. else
  2060. {
  2061. // ++WinSE 27217
  2062. DWORD dwRequired = pstrStatus->QuerySize()
  2063. + MIN_BUFFER_SIZE_FOR_HEADERS;
  2064. if(pbufResponse->QuerySize() < dwRequired)
  2065. {
  2066. if(!pbufResponse->Resize(dwRequired))
  2067. return FALSE;
  2068. pszResp = (CHAR *) pbufResponse->QueryPtr();
  2069. }
  2070. // --WinSE 27217
  2071. strcpy( pszResp, pstrStatus->QueryStr() );
  2072. pszTail = pszResp + strlen(pszResp);
  2073. }
  2074. //
  2075. // "Server: Microsoft/xxx
  2076. //
  2077. APPEND_VER_STR( pszTail );
  2078. DBG_ASSERT( pbufResponse->QuerySize() >= MIN_BUFFER_SIZE_FOR_HEADERS );
  2079. //
  2080. // Fill in the rest of the headers
  2081. //
  2082. //
  2083. // "Date: <GMT Time>" - Time the response was sent.
  2084. //
  2085. if ( !(dwOptions & HTTPH_NO_DATE ) )
  2086. {
  2087. // build Date: uses Date/Time cache
  2088. pszTail += g_pDateTimeCache->GetFormattedCurrentDateTime( pszTail );
  2089. }
  2090. //
  2091. // Add an expires header and any custom headers if the feature
  2092. // is enabled and the caller wants it. Since we could be adding
  2093. // lots of headers here check for space.
  2094. //
  2095. // Note for filters that send response headers, _pMetaData may
  2096. // be NULL at this point
  2097. //
  2098. if (!(dwOptions & HTTPH_NO_CUSTOM))
  2099. {
  2100. cbCustom = _pMetaData ? _pMetaData->QueryHeaders()->QueryCB() : 0;
  2101. }
  2102. else
  2103. {
  2104. cbCustom = 0;
  2105. }
  2106. if ( dwOptions & HTTPH_SEND_GLOBAL_EXPIRE )
  2107. {
  2108. if (!_bForceNoCache)
  2109. {
  2110. cbExpire = _pMetaData->QueryExpireMaxLength() +
  2111. _pMetaData->QueryCacheControlHeaderLength();
  2112. }
  2113. else
  2114. {
  2115. cbExpire = NO_CACHE_HEADER_SIZE;
  2116. }
  2117. }
  2118. else
  2119. {
  2120. cbExpire = 0;
  2121. }
  2122. if ( (cb = cbCustom + cbExpire) != 0 )
  2123. {
  2124. cb += POST_CUSTOM_HEADERS_SIZE;
  2125. // Find out how many bytes are left in the response buffer.
  2126. cbLeft = pbufResponse->QuerySize() - DIFF(pszTail - pszResp);
  2127. if (cb > cbLeft) {
  2128. // Not enough left, try to resize the buffer.
  2129. if ( !pbufResponse->Resize( pbufResponse->QuerySize() - cbLeft + cb + 1))
  2130. {
  2131. // Couldn't resize, fail.
  2132. return FALSE;
  2133. }
  2134. pszTail = (CHAR *) pbufResponse->QueryPtr() + (pszTail - pszResp);
  2135. // Update pszResp, in case it's used later.
  2136. pszResp = (CHAR *) pbufResponse->QueryPtr();
  2137. }
  2138. if ( cbCustom )
  2139. {
  2140. memcpy( pszTail, _pMetaData->QueryHeaders()->QueryStr(), cbCustom + 1);
  2141. pszTail += cbCustom;
  2142. }
  2143. if ( cbExpire )
  2144. {
  2145. DWORD dwExpireHeaderLength;
  2146. FILETIME ftNow;
  2147. DWORD dwStaticMaxAge;
  2148. DWORD dwExpireMode;
  2149. DWORD dwDelta;
  2150. if ( !fSysTimeValid )
  2151. {
  2152. ::IISGetCurrentTimeAsFileTime(&ftSysTime);
  2153. fSysTimeValid = TRUE;
  2154. }
  2155. dwExpireHeaderLength = _pMetaData->QueryExpireHeaderLength();
  2156. if (!_bForceNoCache)
  2157. {
  2158. dwExpireMode = _pMetaData->QueryExpireMode();
  2159. if (_pMetaData->QueryCacheControlHeaderLength() != 0)
  2160. {
  2161. memcpy( pszTail, _pMetaData->QueryCacheControlHeader(),
  2162. _pMetaData->QueryCacheControlHeaderLength() + 1 );
  2163. pszTail += _pMetaData->QueryCacheControlHeaderLength();
  2164. }
  2165. }
  2166. else
  2167. {
  2168. memcpy(pszTail, "Cache-Control: no-cache,no-transform\r\n",
  2169. sizeof("Cache-Control: no-cache,no-transform\r\n"));
  2170. pszTail += sizeof("Cache-Control: no-cache,no-transform\r\n") - 1;
  2171. dwExpireMode = EXPIRE_MODE_DYNAMIC;
  2172. }
  2173. switch ( dwExpireMode )
  2174. {
  2175. case EXPIRE_MODE_STATIC:
  2176. if (!_pMetaData->QueryConfigNoCache() &&
  2177. !_pMetaData->QueryHaveMaxAge())
  2178. {
  2179. //
  2180. // Don't have a pre-configured max-age or no-cache
  2181. // header. Compute the proper one now.
  2182. LONGLONG llNow;
  2183. llNow = *(LONGLONG *)&ftSysTime;
  2184. if (llNow < _pMetaData->QueryExpireTime().QuadPart)
  2185. {
  2186. llNow = _pMetaData->QueryExpireTime().QuadPart - llNow;
  2187. llNow /= FILETIME_1_SECOND; // Convert to seconds.
  2188. if ( llNow > (LONGLONG)0xffffffff)
  2189. {
  2190. dwStaticMaxAge = 0xfffffff;
  2191. }
  2192. else
  2193. {
  2194. dwStaticMaxAge = (DWORD)llNow;
  2195. }
  2196. }
  2197. else
  2198. {
  2199. dwStaticMaxAge = 0;
  2200. }
  2201. if (dwStaticMaxAge != 0)
  2202. {
  2203. APPEND_NUMERIC_HEADER(pszTail, "max-age=",
  2204. dwStaticMaxAge, "\r\n");
  2205. }
  2206. else
  2207. {
  2208. APPEND_STRING(pszTail, "no-cache\r\n");
  2209. }
  2210. }
  2211. memcpy( pszTail, _pMetaData->QueryExpireHeader(),
  2212. dwExpireHeaderLength + 1 );
  2213. pszTail += dwExpireHeaderLength;
  2214. break;
  2215. case EXPIRE_MODE_DYNAMIC:
  2216. if (!_bForceNoCache)
  2217. {
  2218. dwDelta = _pMetaData->QueryExpireDelta();
  2219. }
  2220. else
  2221. {
  2222. dwDelta = 0;
  2223. }
  2224. if ( !::FileTimeToGMTEx( ftSysTime,
  2225. achTime,
  2226. sizeof(achTime),
  2227. dwDelta ))
  2228. {
  2229. return FALSE;
  2230. }
  2231. APPEND_STRING( pszTail, "Expires: " );
  2232. cb = strlen( achTime );
  2233. memcpy( pszTail, achTime, cb );
  2234. pszTail += cb;
  2235. APPEND_STRING( pszTail, "\r\n" );
  2236. break;
  2237. default:
  2238. break;
  2239. }
  2240. }
  2241. }
  2242. //
  2243. // "Connection: keep-alive" - Indicate if the server accepted the
  2244. // session modifier by reflecting it back to the client
  2245. //
  2246. if ( IsKeepConnSet() )
  2247. {
  2248. if (!IsOneOne() && !(dwOptions & HTTPH_NO_CONNECTION))
  2249. {
  2250. APPEND_STRING( pszTail, "Connection: keep-alive\r\n" );
  2251. }
  2252. } else
  2253. {
  2254. if (IsOneOne() && !(dwOptions & HTTPH_NO_CONNECTION))
  2255. {
  2256. APPEND_STRING( pszTail, "Connection: close\r\n" );
  2257. }
  2258. }
  2259. if (dwOptions & HTTPH_SEND_GLOBAL_EXPIRE)
  2260. {
  2261. //
  2262. // Check to see if we need to send a Content-Location: or
  2263. // Vary: header.
  2264. if (_bSendContentLocation)
  2265. {
  2266. CHAR *pszHostName;
  2267. DWORD cbHostNameLength;
  2268. pszHostName = QueryHostAddr();
  2269. cbHostNameLength = strlen(pszHostName);
  2270. dwSizeUsed = DIFF(pszTail - pszResp);
  2271. if ( !pbufResponse->Resize(dwSizeUsed + POST_CUSTOM_HEADERS_SIZE +
  2272. sizeof("Content-Location: https:// \r\n") + sizeof(":65536") +
  2273. cbHostNameLength + _strRawURL.QueryCB()))
  2274. {
  2275. // Couldn't resize, fail.
  2276. return FALSE;
  2277. }
  2278. pszResp = (CHAR *) pbufResponse->QueryPtr();
  2279. pszTail = pszResp + dwSizeUsed;
  2280. // WinSE 5600
  2281. SHORT sPort = QueryClientConn()->QueryPort();
  2282. CHAR szPort[sizeof(":65536")];
  2283. DWORD szPortLen=0;
  2284. if (QueryClientConn()->IsSecurePort())
  2285. {
  2286. if (sPort != 443 )
  2287. {
  2288. szPortLen=wsprintf( szPort, ":%d", (USHORT) sPort );
  2289. }
  2290. }
  2291. else
  2292. {
  2293. if ( sPort != QueryW3Instance()->QueryDefaultPort() )
  2294. {
  2295. szPortLen=wsprintf( szPort, ":%d", (USHORT) sPort );
  2296. }
  2297. }
  2298. if ( cbHostNameLength != 0 )
  2299. {
  2300. if (QueryClientConn()->IsSecurePort())
  2301. {
  2302. APPEND_STRING(pszTail, "Content-Location: https://");
  2303. }
  2304. else
  2305. {
  2306. APPEND_STRING(pszTail, "Content-Location: http://");
  2307. }
  2308. memcpy(pszTail, pszHostName, cbHostNameLength + 1);
  2309. if ( szPortLen )
  2310. {
  2311. memcpy(pszTail+cbHostNameLength,szPort,szPortLen+1);
  2312. }
  2313. pszTail += cbHostNameLength + szPortLen;
  2314. }
  2315. else
  2316. {
  2317. APPEND_STRING(pszTail, "Content-Location: ");
  2318. }
  2319. APPEND_STR_HEADER(pszTail, "", _strRawURL, "\r\n");
  2320. }
  2321. if (_bSendVary)
  2322. {
  2323. dwSizeUsed = DIFF(pszTail - pszResp);
  2324. if ( !pbufResponse->Resize(dwSizeUsed + POST_CUSTOM_HEADERS_SIZE +
  2325. sizeof("Vary: *\r\n")) )
  2326. {
  2327. // Couldn't resize, fail.
  2328. return FALSE;
  2329. }
  2330. pszResp = (CHAR *) pbufResponse->QueryPtr();
  2331. pszTail = pszResp + dwSizeUsed;
  2332. APPEND_STRING(pszTail, "Vary: *\r\n");
  2333. }
  2334. }
  2335. // Authentication headers -- indicate the server requests authentication
  2336. if ( IsAuthenticationRequested() )
  2337. {
  2338. STR strAuthHdrs;
  2339. if ( !AppendAuthenticationHdrs( &strAuthHdrs,
  2340. pfFinished ))
  2341. {
  2342. return FALSE;
  2343. }
  2344. if ( *pfFinished )
  2345. {
  2346. return TRUE;
  2347. }
  2348. if ( !QueryDenialHeaders()->IsEmpty() )
  2349. {
  2350. if ( !strAuthHdrs.Append( QueryDenialHeaders()->QueryStr() ) )
  2351. {
  2352. return FALSE;
  2353. }
  2354. }
  2355. dwSizeUsed = DIFF(pszTail - pszResp);
  2356. if ( !pbufResponse->Resize(dwSizeUsed + strAuthHdrs.QueryCB() + 1 ) )
  2357. {
  2358. // Couldn't resize, fail.
  2359. return FALSE;
  2360. }
  2361. pszResp = (CHAR *) pbufResponse->QueryPtr();
  2362. pszTail = pszResp + dwSizeUsed;
  2363. memcpy( pszTail,
  2364. strAuthHdrs.QueryStr(),
  2365. strAuthHdrs.QueryCB() + 1 );
  2366. pszTail += strAuthHdrs.QueryCB();
  2367. }
  2368. else if ( !_strAuthInfo.IsEmpty() )
  2369. {
  2370. dwSizeUsed = DIFF(pszTail - pszResp);
  2371. if ( !pbufResponse->Resize(dwSizeUsed +
  2372. sizeof("Proxy-Authenticate: \r\n") +
  2373. _strAuthInfo.QueryCB()) )
  2374. {
  2375. // Couldn't resize, fail.
  2376. return FALSE;
  2377. }
  2378. pszResp = (CHAR *) pbufResponse->QueryPtr();
  2379. pszTail = pszResp + dwSizeUsed;
  2380. pszTail += wsprintf( pszTail,
  2381. "%s: %s\r\n",
  2382. (IsProxyRequest() ? "Proxy-Authenticate" :
  2383. "WWW-Authenticate"),
  2384. _strAuthInfo.QueryStr() );
  2385. }
  2386. //
  2387. // Append headers specified by filters
  2388. //
  2389. if ( !QueryAdditionalRespHeaders()->IsEmpty() )
  2390. {
  2391. cb = QueryAdditionalRespHeaders()->QueryCB() + 1;
  2392. cbLeft = pbufResponse->QuerySize() - DIFF(pszTail - pszResp);
  2393. if ( cb > cbLeft )
  2394. {
  2395. if ( !pbufResponse->Resize( pbufResponse->QuerySize() + cb ))
  2396. {
  2397. return FALSE;
  2398. }
  2399. pszTail = (CHAR *) pbufResponse->QueryPtr() + (pszTail - pszResp);
  2400. }
  2401. memcpy( pszTail, QueryAdditionalRespHeaders()->QueryStr(), cb );
  2402. }
  2403. return TRUE;
  2404. }
  2405. BOOL WINAPI
  2406. DeleteFunc(
  2407. CtxtHandle* pH,
  2408. PVOID pF
  2409. )
  2410. /*++
  2411. Routine Description:
  2412. Notification of SSPI security context destruction
  2413. Arguments:
  2414. pH - SSPI security context
  2415. pF - HTTP_REQ_BASE to notify
  2416. Return Value:
  2417. TRUE on success, FALSE on failure
  2418. --*/
  2419. {
  2420. return ((HTTP_REQ_BASE*)pF)->NotifyRequestSecurityContextClose( pH );
  2421. }
  2422. BOOL
  2423. HTTP_REQ_BASE::SetCertificateInfo(
  2424. IN PHTTP_FILTER_CERTIFICATE_INFO pData,
  2425. IN CtxtHandle *pCtxt,
  2426. IN HANDLE hPrimaryToken,
  2427. IN HTTP_FILTER_DLL* pFilter
  2428. )
  2429. /*++
  2430. Routine Description:
  2431. Set SSL/PCT SSPI security context & access token
  2432. Arguments:
  2433. pData - ptr to certificate info
  2434. pCtxt - SSPI security context
  2435. hPrimaryToken - access token bound to SSPI security context
  2436. pFilter - calling filter
  2437. Return Value:
  2438. TRUE on success, FALSE on failure
  2439. --*/
  2440. {
  2441. if ( pCtxt != NULL )
  2442. {
  2443. if ( hPrimaryToken == IIS_ACCESS_DENIED_HANDLE )
  2444. {
  2445. _fInvalidAccessToken = TRUE;
  2446. return TRUE;
  2447. }
  2448. _pAuthFilter = NULL;
  2449. W3_SERVER_INSTANCE *pInstance = QueryW3InstanceAggressively();
  2450. if ( hPrimaryToken != NULL )
  2451. {
  2452. ResetAuth( TRUE );
  2453. _pAuthFilter = pFilter;
  2454. if ( !_tcpauth.SetSecurityContextToken( pCtxt,
  2455. hPrimaryToken,
  2456. DeleteFunc,
  2457. (PVOID)this,
  2458. ( pInstance ?
  2459. pInstance->GetAndReferenceSSLInfoObj() :
  2460. NULL ) ) )
  2461. {
  2462. _pAuthFilter = NULL;
  2463. return FALSE;
  2464. }
  2465. _strAuthType.Copy( "SSL/PCT", (sizeof( "SSL/PCT") - 1) );
  2466. _fLoggedOn = TRUE;
  2467. _fAuthCert = TRUE;
  2468. _dwSslNegoFlags |= SSLNEGO_MAP;
  2469. _strPassword.Reset();
  2470. QueryW3StatsObj()->IncrNonAnonymousUsers();
  2471. //
  2472. // Get the user name
  2473. //
  2474. if ( !_tcpauth.QueryUserName( &_strUserName ) ||
  2475. (_strUserName.SetLen( strlen(_strUserName.QueryStr()) ),
  2476. !_strUnmappedUserName.Copy( _strUserName )) )
  2477. {
  2478. DBGPRINTF(( DBG_CONTEXT,
  2479. "[SetCertificateInfo] Getting username failed, error %d\n",
  2480. GetLastError() ));
  2481. return FALSE;
  2482. }
  2483. }
  2484. else
  2485. {
  2486. if ( !_tcpauth.SetSecurityContextToken( pCtxt,
  2487. hPrimaryToken,
  2488. DeleteFunc,
  2489. (PVOID)this,
  2490. ( pInstance ?
  2491. pInstance->GetAndReferenceSSLInfoObj() :
  2492. NULL ) ) )
  2493. {
  2494. return FALSE;
  2495. }
  2496. }
  2497. return TRUE;
  2498. }
  2499. SetLastError( ERROR_INVALID_PARAMETER );
  2500. DBG_ASSERT( FALSE );
  2501. return FALSE;
  2502. }
  2503. BOOL
  2504. HTTP_REQ_BASE::CheckValidSSPILogin(
  2505. VOID
  2506. )
  2507. {
  2508. // Check if guest account
  2509. if ( _tcpauth.IsGuest( FALSE ) )
  2510. {
  2511. if ( !(QueryAuthentication() & INET_INFO_AUTH_ANONYMOUS) )
  2512. {
  2513. SetLastError( ERROR_LOGON_FAILURE );
  2514. SetDeniedFlags( SF_DENIED_LOGON | SF_DENIED_BY_CONFIG );
  2515. _fAuthenticating = FALSE;
  2516. _fLoggedOn = FALSE;
  2517. SetKeepConn( FALSE );
  2518. return FALSE;
  2519. }
  2520. //
  2521. // cancel current authorization & authentication
  2522. //
  2523. _HeaderList.FastMapCancel( HM_AUT );
  2524. _fLoggedOn = FALSE;
  2525. _fInvalidAccessToken = FALSE;
  2526. _fClearTextPass = FALSE;
  2527. _fAnonymous = FALSE;
  2528. _fAuthenticating = FALSE;
  2529. _fAuthTypeDigest = FALSE;
  2530. _fAuthSystem = FALSE;
  2531. _fAuthCert = FALSE;
  2532. _tcpauth.Reset();
  2533. _strAuthType.Reset();
  2534. _strUserName.Reset();
  2535. _strPassword.Reset();
  2536. _strUnmappedUserName.Reset();
  2537. // return as if no authorization had been seen
  2538. return TRUE;
  2539. }
  2540. QueryW3StatsObj()->IncrNonAnonymousUsers();
  2541. //
  2542. // Get the user name
  2543. //
  2544. if ( !_tcpauth.QueryUserName( &_strUserName ) ||
  2545. !_strUnmappedUserName.Copy( _strUserName ) )
  2546. {
  2547. DBGPRINTF(( DBG_CONTEXT,
  2548. "[OnAuthorization] Getting username failed, error %d\n",
  2549. GetLastError() ));
  2550. return FALSE;
  2551. }
  2552. return TRUE;
  2553. }
  2554. BOOL
  2555. HTTP_REQ_BASE::CheckForBasicAuthenticationHeader(
  2556. LPSTR pszHeaders
  2557. )
  2558. /*++
  2559. Routine Description:
  2560. Parse header for realm info in Basic authentication scheme
  2561. Arguments:
  2562. pszHeaders - headers to parse
  2563. Return Value:
  2564. TRUE on success, FALSE on failure
  2565. --*/
  2566. {
  2567. UINT cHeaders = strlen( pszHeaders );
  2568. UINT cLine;
  2569. UINT cToNext;
  2570. LPSTR pEOL;
  2571. int ch;
  2572. while ( cHeaders )
  2573. {
  2574. if ( (pEOL = (LPSTR)memchr( pszHeaders, '\n', cHeaders)) == NULL )
  2575. {
  2576. cLine = cHeaders;
  2577. cToNext = cHeaders;
  2578. }
  2579. else
  2580. {
  2581. cLine = DIFF(pEOL - pszHeaders);
  2582. cToNext = cLine + 1;
  2583. if ( pEOL != pszHeaders && pEOL[-1] == '\r' )
  2584. {
  2585. --cLine;
  2586. }
  2587. }
  2588. if ( !_strnicmp( pszHeaders,
  2589. "WWW-Authenticate",
  2590. sizeof("WWW-Authenticate")-1 ) )
  2591. {
  2592. LPSTR pS = pszHeaders + sizeof("WWW-Authenticate:") - 1;
  2593. UINT cS = cLine - (sizeof("WWW-Authenticate:") - 1);
  2594. while ( cS && isspace( (UCHAR)(*pS) ) )
  2595. {
  2596. ++pS;
  2597. --cS;
  2598. }
  2599. if ( !_strnicmp( pS, "basic", sizeof("basic")-1 ) )
  2600. {
  2601. while ( cS && isalpha( (UCHAR)(*pS) ) )
  2602. {
  2603. ++pS;
  2604. --cS;
  2605. }
  2606. while ( cS && !isalpha( (UCHAR)(*pS) ) )
  2607. {
  2608. ++pS;
  2609. --cS;
  2610. }
  2611. if ( !_strnicmp( pS, "realm", sizeof("realm")-1 ) )
  2612. {
  2613. // check if realm value specified
  2614. while ( cS && *pS != '=' )
  2615. {
  2616. ++pS;
  2617. --cS;
  2618. }
  2619. #if 0
  2620. if ( cS )
  2621. {
  2622. ++pS;
  2623. --cS;
  2624. // locate start of realm value
  2625. while ( cS )
  2626. {
  2627. --cS;
  2628. if ( *pS++ == '"' )
  2629. {
  2630. break;
  2631. }
  2632. }
  2633. LPSTR pR = pS;
  2634. // locate end of realm value
  2635. while ( cS && *pS != '"' )
  2636. {
  2637. ++pS;
  2638. --cS;
  2639. }
  2640. ch = *pS;
  2641. *pS = '\0';
  2642. // pR contains zero-delimited realm
  2643. *pS = ch;
  2644. }
  2645. #endif
  2646. _fBasicRealm = TRUE;
  2647. }
  2648. return TRUE;
  2649. }
  2650. }
  2651. cHeaders -= cToNext;
  2652. pszHeaders += cToNext;
  2653. }
  2654. return FALSE;
  2655. }
  2656. BOOL
  2657. HTTP_REQ_BASE::LogonAsSystem(
  2658. VOID
  2659. )
  2660. /*++
  2661. Routine Description:
  2662. Associate the system account with the current request
  2663. AUTH_TYPE and LOGON_USER are set to "SYSTEM" if success
  2664. Arguments:
  2665. None
  2666. Return Value:
  2667. TRUE on success, FALSE on failure
  2668. --*/
  2669. {
  2670. HANDLE hTok;
  2671. if ( _fLoggedOn )
  2672. {
  2673. if ( _fAnonymous ) {
  2674. QueryW3StatsObj()->DecrCurrentAnonymousUsers();
  2675. } else {
  2676. QueryW3StatsObj()->DecrCurrentNonAnonymousUsers();
  2677. }
  2678. }
  2679. ResetAuth( FALSE );
  2680. if ( !IISDuplicateTokenEx( g_hSysAccToken,
  2681. TOKEN_ALL_ACCESS,
  2682. NULL,
  2683. SecurityImpersonation,
  2684. TokenPrimary,
  2685. &hTok ))
  2686. {
  2687. return FALSE;
  2688. }
  2689. if ( _tcpauth.SetAccessToken( hTok, NULL ) )
  2690. {
  2691. _fLoggedOn = TRUE;
  2692. _fMappedAcct = TRUE;
  2693. _fAuthSystem = TRUE;
  2694. _HeaderList.FastMapCancel( HM_AUT );
  2695. _HeaderList.FastMapCancel( HM_CON );
  2696. SetKeepConn( FALSE );
  2697. _strAuthType.Copy( PSZ_KWD_SYSTEM, LEN_PSZ_KWD_SYSTEM);
  2698. _strUserName.Copy( PSZ_KWD_SYSTEM, LEN_PSZ_KWD_SYSTEM);
  2699. _strPassword.Reset();
  2700. QueryW3StatsObj()->IncrNonAnonymousUsers();
  2701. //_strUnmappedUserName will contains real user name
  2702. _fSingleRequestAuth = TRUE;
  2703. return TRUE;
  2704. }
  2705. else
  2706. {
  2707. CloseHandle( hTok );
  2708. }
  2709. return FALSE;
  2710. }
  2711. GENERIC_MAPPING VrootFileGenericMapping =
  2712. {
  2713. FILE_GENERIC_READ,
  2714. FILE_GENERIC_WRITE,
  2715. FILE_GENERIC_EXECUTE,
  2716. FILE_ALL_ACCESS
  2717. };
  2718. VOID
  2719. HTTP_REQ_BASE::ReleaseCacheInfo(
  2720. VOID
  2721. )
  2722. /*++
  2723. Description:
  2724. Release ptr to URI & metadata cache
  2725. Arguments:
  2726. None
  2727. Returns:
  2728. Nothing
  2729. --*/
  2730. {
  2731. if ( g_fGetBackTraces )
  2732. {
  2733. ULONG ulHash;
  2734. RtlWalkFrameChain( m_ppvFrames,
  2735. MAX_BACKTRACE_FRAMES,
  2736. 0 );
  2737. }
  2738. if ( _pURIInfo != NULL)
  2739. {
  2740. if (_pURIInfo->bIsCached)
  2741. {
  2742. TsCheckInCachedBlob( _pURIInfo );
  2743. } else
  2744. {
  2745. TsFree(QueryW3Instance()->GetTsvcCache(), _pURIInfo );
  2746. }
  2747. }
  2748. else
  2749. {
  2750. if (_pMetaData != NULL)
  2751. {
  2752. TsFreeMetaData(_pMetaData->QueryCacheInfo() );
  2753. }
  2754. }
  2755. _pMetaData = NULL;
  2756. _pURIInfo = NULL;
  2757. }
  2758. BOOL
  2759. HTTP_REQ_BASE::VrootAccessCheck(
  2760. PW3_METADATA pMetaData,
  2761. DWORD dwDesiredAccess
  2762. )
  2763. /*++
  2764. Description:
  2765. Check that the current access token have access to the
  2766. ACL of the current virtual root
  2767. Arguments:
  2768. pMetaData - points to metadata object
  2769. dwDesiredAccess - access right, e.g. FILE_GENERIC_READ
  2770. Returns:
  2771. TRUE if access granted, FALSE if access denied
  2772. --*/
  2773. {
  2774. DWORD dwGrantedAccess;
  2775. BYTE PrivSet[400];
  2776. DWORD cbPrivilegeSet = sizeof(PrivSet);
  2777. BOOL fAccessGranted;
  2778. if ( pMetaData && pMetaData->QueryAcl() &&
  2779. (!::AccessCheck( pMetaData->QueryAcl(),
  2780. QueryImpersonationHandle(),
  2781. dwDesiredAccess,
  2782. &VrootFileGenericMapping,
  2783. (PRIVILEGE_SET *) &PrivSet,
  2784. &cbPrivilegeSet,
  2785. &dwGrantedAccess,
  2786. &fAccessGranted ) ||
  2787. !fAccessGranted) )
  2788. {
  2789. SetLastError( ERROR_ACCESS_DENIED );
  2790. return FALSE;
  2791. }
  2792. return TRUE;
  2793. }
  2794. BOOL
  2795. ReadEntireFile(
  2796. CHAR *pszFileName,
  2797. TSVC_CACHE &Cache,
  2798. HANDLE User,
  2799. BUFFER *pBuf,
  2800. DWORD *pdwBytesRead
  2801. )
  2802. /*++
  2803. Description:
  2804. Read an entire file into the specified buffer.
  2805. Arguments:
  2806. pszFileName - File name of file to be read.
  2807. Cache - Tsunami cache info for file read.
  2808. User - User token for opening the file.
  2809. pBuf - Pointer to buffer to be read into.
  2810. Returns:
  2811. TRUE if we read it, FALSE otherwise.
  2812. --*/
  2813. {
  2814. HANDLE hFile;
  2815. SECURITY_ATTRIBUTES sa;
  2816. DWORD dwFileSize, dwFileSizeHigh;
  2817. DWORD dwCurrentBufSize;
  2818. BOOL bFileReadSuccess;
  2819. DWORD dwBytesRead;
  2820. const CHAR *pszFile[2];
  2821. DWORD dwError;
  2822. CHAR szError[17];
  2823. dwError = NO_ERROR;
  2824. if( !g_fIsWindows95 && !::ImpersonateLoggedOnUser( User ) ) {
  2825. dwError = GetLastError();
  2826. hFile = INVALID_HANDLE_VALUE;
  2827. } else {
  2828. sa.nLength = sizeof(sa);
  2829. sa.lpSecurityDescriptor = NULL;
  2830. sa.bInheritHandle = FALSE;
  2831. hFile = CreateFile(
  2832. pszFileName,
  2833. GENERIC_READ,
  2834. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2835. &sa,
  2836. OPEN_EXISTING,
  2837. FILE_FLAG_SEQUENTIAL_SCAN,
  2838. NULL
  2839. );
  2840. if( hFile == INVALID_HANDLE_VALUE ) {
  2841. dwError = GetLastError();
  2842. }
  2843. if ( !g_fIsWindows95 ) {
  2844. ::RevertToSelf();
  2845. }
  2846. }
  2847. if( hFile == INVALID_HANDLE_VALUE ) {
  2848. DWORD dwEventType;
  2849. WORD dwParamCount;
  2850. ASSERT( dwError != NO_ERROR );
  2851. pszFile[0] = pszFileName;
  2852. dwParamCount = 1;
  2853. // Couldn't read the error file for some reason, so just bail out
  2854. // now.
  2855. if (dwError == ERROR_ACCESS_DENIED)
  2856. {
  2857. // Couldn't read the file due to lack of access. Log an event,
  2858. // and map the error to invalid configuration to prevent
  2859. // us from initiating an HTTP authentication sequence.
  2860. dwEventType = W3_EVENT_CANNOT_READ_FILE_SECURITY;
  2861. dwError = ERROR_INVALID_PARAMETER;
  2862. }
  2863. else
  2864. {
  2865. if ( dwError == ERROR_FILE_NOT_FOUND ||
  2866. dwError == ERROR_PATH_NOT_FOUND
  2867. )
  2868. {
  2869. dwEventType = W3_EVENT_CANNOT_READ_FILE_EXIST;
  2870. }
  2871. else
  2872. {
  2873. dwEventType = W3_EVENT_CANNOT_READ_FILE;
  2874. _itoa( dwError, szError, 10 );
  2875. pszFile[1] = szError;
  2876. dwParamCount = 2;
  2877. }
  2878. }
  2879. g_pInetSvc->LogEvent( dwEventType,
  2880. dwParamCount,
  2881. pszFile,
  2882. 0 );
  2883. SetLastError(dwError);
  2884. return FALSE;
  2885. }
  2886. // Query the size. If it's too large, fail.
  2887. dwFileSize = ::GetFileSize( hFile, &dwFileSizeHigh );
  2888. if (dwFileSizeHigh != 0 ||
  2889. dwFileSize > MAX_CUSTOM_ERROR_FILE_SIZE)
  2890. {
  2891. CloseHandle( hFile );
  2892. pszFile[0] = pszFileName;
  2893. pszFile[1] = CONST_TO_STRING(MAX_CUSTOM_ERROR_FILE_SIZE);
  2894. g_pInetSvc->LogEvent( W3_EVENT_CANNOT_READ_FILE_SIZE,
  2895. 2,
  2896. pszFile,
  2897. 0 );
  2898. SetLastError( ERROR_INVALID_DATA );
  2899. return FALSE;
  2900. }
  2901. dwCurrentBufSize = strlen( (CHAR *)pBuf->QueryPtr() );
  2902. if ( !pBuf->Resize(dwCurrentBufSize + dwFileSize + 1) )
  2903. {
  2904. // Couldn't resize the buffer, so fail.
  2905. CloseHandle( hFile );
  2906. pszFile[0] = pszFileName;
  2907. g_pInetSvc->LogEvent( W3_EVENT_CANNOT_READ_FILE_MEMORY,
  2908. 1,
  2909. pszFile,
  2910. 0 );
  2911. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  2912. return FALSE;
  2913. }
  2914. // Now read the file.
  2915. bFileReadSuccess = ::ReadFile( hFile,
  2916. (CHAR *)pBuf->QueryPtr() + dwCurrentBufSize,
  2917. dwFileSize,
  2918. &dwBytesRead,
  2919. NULL
  2920. );
  2921. dwError = GetLastError();
  2922. // We're done with the file, so close the handle now.
  2923. CloseHandle( hFile );
  2924. if (!bFileReadSuccess || (dwBytesRead != dwFileSize))
  2925. {
  2926. // There was some sort of error in the file read, so bail out.
  2927. _itoa( dwError, szError, 10 );
  2928. pszFile[0] = pszFileName;
  2929. pszFile[1] = szError;
  2930. g_pInetSvc->LogEvent( W3_EVENT_CANNOT_READ_FILE,
  2931. 2,
  2932. pszFile,
  2933. 0 );
  2934. return FALSE;
  2935. }
  2936. CHAR *Temp = (CHAR *)pBuf->QueryPtr();
  2937. *(Temp + dwCurrentBufSize + dwBytesRead) = '\0';
  2938. *pdwBytesRead = dwBytesRead;
  2939. return TRUE;
  2940. }
  2941. BOOL
  2942. HTTP_REQ_BASE::CheckCustomError(
  2943. BUFFER *pBuf,
  2944. DWORD dwErr,
  2945. DWORD dwSubError,
  2946. BOOL *pfFinished,
  2947. DWORD *pdwMsgSize,
  2948. BOOL bCheckURL
  2949. )
  2950. /*++
  2951. Description:
  2952. Check for a custom error on message or URL for a specific error. If
  2953. we find an custom error message, fill in the buffer with the message.
  2954. If we find a URL, we'll reprocess the URL to handle the error.
  2955. Arguments:
  2956. pBuf - Pointer to buffer to fill in with error message.
  2957. dwErr - Error code to be checked.
  2958. pfFinished - Pointer to boolean. Set to TRUE if no further processing
  2959. is required, FALSE otherwise. If it's set to FALSE then
  2960. the caller still needs to send the buffer. Valid iff
  2961. this function returns TRUE.
  2962. bCheckURL - TRUE if we are to check for a URL.
  2963. Returns:
  2964. TRUE if there was a custom error for this error, FALSE otherwise.
  2965. --*/
  2966. {
  2967. PCUSTOM_ERROR_ENTRY pErrEntry;
  2968. DWORD dwLogHttpResponse;
  2969. DWORD dwLogWinError;
  2970. // First make sure we're not already processing a custom error.
  2971. if (_bProcessingCustomError)
  2972. {
  2973. return FALSE;
  2974. }
  2975. // Make sure we've got MetaData.
  2976. //
  2977. // CODEWORK - Fix this so we try and find the metadata for the the root VR
  2978. // in this case. We'll need to fix FindAndReferenceInstance etc. We'll
  2979. // still have to fail if we don't have an instance.
  2980. if (QueryMetaData() == NULL)
  2981. {
  2982. return FALSE;
  2983. }
  2984. // Now lookup the error code to see if we have a custom error.
  2985. pErrEntry = QueryMetaData()->LookupCustomError(dwErr, dwSubError);
  2986. if (pErrEntry == NULL)
  2987. {
  2988. // No custom error, return FALSE.
  2989. return FALSE;
  2990. }
  2991. if (pErrEntry->IsFileError())
  2992. {
  2993. STR strMimeType;
  2994. DWORD dwCurrentSize;
  2995. DWORD dwSizeNeeded;
  2996. CHAR *pszHeader;
  2997. if (!SelectMimeMappingForFileExt(g_pInetSvc,
  2998. (const CHAR *)pErrEntry->QueryErrorFileName(),
  2999. &strMimeType
  3000. ))
  3001. {
  3002. DBGPRINTF(( DBG_CONTEXT,
  3003. "CheckCustomError: Unable to get MIME type for %s\n",
  3004. pErrEntry->QueryErrorFileName()));
  3005. return FALSE;
  3006. }
  3007. dwCurrentSize = strlen((CHAR *)pBuf->QueryPtr());
  3008. dwSizeNeeded = dwCurrentSize + 1 + sizeof("Content-Type: ") - 1 +
  3009. strMimeType.QueryCB() + sizeof("\r\n\r\n") - 1;
  3010. if ((pBuf->QuerySize() < dwSizeNeeded) && !pBuf->Resize(dwSizeNeeded))
  3011. {
  3012. DBGPRINTF(( DBG_CONTEXT,
  3013. "CheckCustomError: Buffer too small and unable to resize\n"));
  3014. return FALSE;
  3015. }
  3016. pszHeader = (CHAR *)pBuf->QueryPtr() + dwCurrentSize;
  3017. APPEND_PSZ_HEADER(pszHeader, "Content-Type: ", strMimeType.QueryStr(), "\r\n\r\n");
  3018. if (!ReadEntireFile(pErrEntry->QueryErrorFileName(),
  3019. QueryW3Instance()->GetTsvcCache(),
  3020. g_hSysAccToken,
  3021. pBuf,
  3022. pdwMsgSize))
  3023. {
  3024. // Have to undo the copy in we did.
  3025. pszHeader = (CHAR *)pBuf->QueryPtr() + dwCurrentSize;
  3026. *pszHeader = '\0';
  3027. return FALSE;
  3028. }
  3029. // Otherwise it worked.
  3030. *pfFinished = FALSE;
  3031. return TRUE;
  3032. }
  3033. else
  3034. {
  3035. // This must be a custom URL. Create a new URL from the custom error
  3036. // that includes the error code as a parameter, and reprocess the URL.
  3037. HTTP_REQUEST *pReq;
  3038. CHAR *Temp = (CHAR *)pBuf->QueryPtr();
  3039. STR strNewURL;
  3040. CHAR szError[20];
  3041. enum CLIENT_CONN_STATE OldConnState;
  3042. CHAR *pszHostName;
  3043. DWORD cbHostNameLength;
  3044. if (!bCheckURL)
  3045. {
  3046. return FALSE;
  3047. }
  3048. if (!strNewURL.Copy( (const CHAR *)pErrEntry->QueryErrorURL() ) )
  3049. {
  3050. return FALSE;
  3051. }
  3052. //
  3053. // Remote URLs are not allowed as custom errors.
  3054. //
  3055. if ( !_strnicmp(strNewURL.QueryStr(),"http://",sizeof("http://")-1) ||
  3056. !_strnicmp(strNewURL.QueryStr(),"https://",sizeof("https://") - 1) )
  3057. {
  3058. DBGPRINTF(( DBG_CONTEXT,
  3059. "CheckCustomError: URL is not Local. Returnig Failure\n"));
  3060. return FALSE;
  3061. }
  3062. if (!strNewURL.Append("?", sizeof("?") - 1))
  3063. {
  3064. return FALSE;
  3065. }
  3066. _itoa(dwErr, szError, 10);
  3067. if (!strNewURL.Append( (const CHAR *)szError) )
  3068. {
  3069. return FALSE;
  3070. }
  3071. if (!strNewURL.Append(";", sizeof(";") - 1))
  3072. {
  3073. return FALSE;
  3074. }
  3075. pszHostName = QueryHostAddr();
  3076. cbHostNameLength = strlen(pszHostName);
  3077. if (cbHostNameLength != 0)
  3078. {
  3079. if (!strNewURL.Append("http://", sizeof("http://") -1) ||
  3080. !strNewURL.Append(pszHostName, cbHostNameLength))
  3081. {
  3082. return FALSE;
  3083. }
  3084. }
  3085. if (!strNewURL.Append(_strRawURL))
  3086. {
  3087. return FALSE;
  3088. }
  3089. *Temp = '\0';
  3090. _bProcessingCustomError = TRUE;
  3091. SetNoCache();
  3092. SetSendVary();
  3093. pReq = (HTTP_REQUEST *)this;
  3094. pReq->CloseGetFile();
  3095. //
  3096. // Need to set the connection state to processing, because we might be
  3097. // disconnecting right now. Save the old state in case the reprocess
  3098. // fails.
  3099. OldConnState = QueryClientConn()->QueryState();
  3100. QueryClientConn()->SetState(CCS_PROCESSING_CLIENT_REQ);
  3101. dwLogHttpResponse = QueryLogHttpResponse();
  3102. dwLogWinError = QueryLogWinError();
  3103. if ( !pReq->ReprocessURL( strNewURL.QueryStr(),
  3104. HTV_GET ))
  3105. {
  3106. //
  3107. // if we failed & state is DOVERB restore to DONE to prevent
  3108. // response from being generated twice (once here and once after doverb
  3109. // processing in DoWork() )
  3110. //
  3111. if ( QueryState() == HTR_DOVERB )
  3112. {
  3113. SetState( HTR_DONE, dwLogHttpResponse, dwLogWinError );
  3114. }
  3115. QueryClientConn()->SetState(OldConnState);
  3116. return FALSE;
  3117. }
  3118. *pfFinished = TRUE;
  3119. return TRUE;
  3120. }
  3121. }
  3122. BOOL
  3123. HTTP_REQ_BASE::IsClientProxy(
  3124. VOID
  3125. )
  3126. /*++
  3127. Description:
  3128. Check if request was issued by a proxy, as determined by following rules :
  3129. - "Via:" header is present (HTTP/1.1)
  3130. - "Forwarded:" header is present (some HTTP/1.0 implementations)
  3131. - "User-Agent:" contains "via ..." (CERN proxy)
  3132. Arguments:
  3133. None
  3134. Returns:
  3135. TRUE if client request was issued by proxy
  3136. --*/
  3137. {
  3138. LPSTR pUA;
  3139. UINT cUA;
  3140. LPSTR pEnd;
  3141. if ( _HeaderList.FastMapQueryValue( HM_VIA ) != NULL ||
  3142. _HeaderList.FastMapQueryValue( HM_FWD ) != NULL )
  3143. {
  3144. return TRUE;
  3145. }
  3146. if ( !IsAtLeastOneOne() &&
  3147. (pUA = (LPSTR)_HeaderList.FastMapQueryValue( HM_UAT )) != NULL )
  3148. {
  3149. cUA = strlen( pUA );
  3150. pEnd = pUA + cUA - (sizeof("ia ")-1);
  3151. //
  3152. // scan for "[Vv]ia[ :]" in User-Agent: header
  3153. //
  3154. while ( pUA < pEnd )
  3155. {
  3156. if ( *pUA == 'V' || *pUA == 'v' )
  3157. {
  3158. if ( pUA[1] == 'i' &&
  3159. pUA[2] == 'a' &&
  3160. (pUA[3] == ' ' || pUA[3] == ':') )
  3161. {
  3162. return TRUE;
  3163. }
  3164. }
  3165. ++pUA;
  3166. }
  3167. }
  3168. return FALSE;
  3169. }
  3170. W3_SERVER_INSTANCE* HTTP_REQ_BASE::QueryW3InstanceAggressively( VOID ) const
  3171. /*++
  3172. Description:
  3173. This tries "aggressively" to find the instance associated with this request.
  3174. If the instance is already set, it returns that; otherwise, it tries to find
  3175. an instance matching the IP/Port # for the connection associated with this
  3176. request.
  3177. This is useful for requests that won't use Host headers eg SSL requests, where
  3178. it may be necessary to determine the instance for a request before it's been
  3179. set by the URL-parsing code.
  3180. Note that the function -DOES NOT- update the _pW3Instance member.
  3181. Arguments:
  3182. None
  3183. Returns:
  3184. Pointer to associated instance if found, NULL if no instance was found.
  3185. --*/
  3186. {
  3187. W3_SERVER_INSTANCE *pInstance = NULL;
  3188. if ( _pW3Instance )
  3189. {
  3190. pInstance = _pW3Instance;
  3191. }
  3192. else
  3193. {
  3194. BOOL fExceeded ;
  3195. //
  3196. // Try specific (IP, port) first, then try to wildcard the IP address.
  3197. // Port # can't be wildcarded.
  3198. //
  3199. IIS_ENDPOINT *pEndPoint = g_pInetSvc->FindAndReferenceEndpoint(
  3200. _pClientConn->QueryPort(),
  3201. _pClientConn->QueryLocalIPAddress(),
  3202. FALSE,
  3203. FALSE );
  3204. if ( !pEndPoint )
  3205. {
  3206. pEndPoint = g_pInetSvc->FindAndReferenceEndpoint( _pClientConn->QueryPort(),
  3207. 0,
  3208. FALSE,
  3209. FALSE );
  3210. }
  3211. if ( pEndPoint )
  3212. {
  3213. pInstance = (W3_SERVER_INSTANCE *) pEndPoint->FindAndReferenceInstance(
  3214. NULL,
  3215. _pClientConn->QueryLocalIPAddress(),
  3216. &fExceeded );
  3217. //
  3218. // FindAndReferenceInstance increments # of connections, and we're not
  3219. // using up a connection
  3220. //
  3221. if ( pInstance )
  3222. {
  3223. pInstance->DecrementCurrentConnections();
  3224. pInstance->Dereference();
  3225. }
  3226. pEndPoint->Dereference();
  3227. }
  3228. }
  3229. return ( pInstance );
  3230. }