Leaked source code of windows server 2003
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.

4890 lines
125 KiB

  1. /*++
  2. Copyright (c) 1998-2002 Microsoft Corporation
  3. Module Name:
  4. ioctl.c
  5. Abstract:
  6. This module implements various IOCTL handlers.
  7. Author:
  8. Keith Moore (keithmo) 10-Jun-1998
  9. Revision History:
  10. Paul McDaniel (paulmcd) 15-Mar-1999 Modified SendResponse
  11. George V. Reilly (GeorgeRe) May 2001 Hardened the IOCTLs
  12. --*/
  13. // Paranoia is the name of the game here. We don't trust anything we get from
  14. // user mode. All data has to be probed inside of a try/except handler.
  15. // Furthermore, we assume that malicious or incompetent users will
  16. // asynchronously change the data at any time, so we attempt to capture as
  17. // much as possible of it in stack variables. If we need to walk through a
  18. // list more than once, we cannot assume that it's the same data the second
  19. // time around. Failure to observe these rules could result in a bugcheck or
  20. // in the usermode code gaining access to kernel data structures.
  21. #include "precomp.h"
  22. #include "ioctlp.h"
  23. #ifdef ALLOC_PRAGMA
  24. #pragma alloc_text( PAGE, UlQueryControlChannelIoctl )
  25. #pragma alloc_text( PAGE, UlSetControlChannelIoctl )
  26. #pragma alloc_text( PAGE, UlCreateConfigGroupIoctl )
  27. #pragma alloc_text( PAGE, UlDeleteConfigGroupIoctl )
  28. #pragma alloc_text( PAGE, UlQueryConfigGroupIoctl )
  29. #pragma alloc_text( PAGE, UlSetConfigGroupIoctl )
  30. #pragma alloc_text( PAGE, UlAddUrlToConfigGroupIoctl )
  31. #pragma alloc_text( PAGE, UlRemoveUrlFromConfigGroupIoctl )
  32. #pragma alloc_text( PAGE, UlRemoveAllUrlsFromConfigGroupIoctl )
  33. #pragma alloc_text( PAGE, UlQueryAppPoolInformationIoctl )
  34. #pragma alloc_text( PAGE, UlSetAppPoolInformationIoctl )
  35. #pragma alloc_text( PAGE, UlReceiveHttpRequestIoctl )
  36. #pragma alloc_text( PAGE, UlReceiveEntityBodyIoctl )
  37. #pragma alloc_text( PAGE, UlSendHttpResponseIoctl )
  38. #pragma alloc_text( PAGE, UlSendEntityBodyIoctl )
  39. #pragma alloc_text( PAGE, UlFlushResponseCacheIoctl )
  40. #pragma alloc_text( PAGE, UlWaitForDemandStartIoctl )
  41. #pragma alloc_text( PAGE, UlWaitForDisconnectIoctl )
  42. #pragma alloc_text( PAGE, UlFilterAcceptIoctl )
  43. #pragma alloc_text( PAGE, UlFilterCloseIoctl )
  44. #pragma alloc_text( PAGE, UlFilterRawReadIoctl )
  45. #pragma alloc_text( PAGE, UlFilterRawWriteIoctl )
  46. #pragma alloc_text( PAGE, UlFilterAppReadIoctl )
  47. #pragma alloc_text( PAGE, UlFilterAppWriteIoctl )
  48. #pragma alloc_text( PAGE, UlReceiveClientCertIoctl )
  49. #pragma alloc_text( PAGE, UlGetCountersIoctl )
  50. #pragma alloc_text( PAGE, UlAddFragmentToCacheIoctl )
  51. #pragma alloc_text( PAGE, UlReadFragmentFromCacheIoctl )
  52. #pragma alloc_text( PAGE, UcSetServerContextInformationIoctl )
  53. #pragma alloc_text( PAGE, UcQueryServerContextInformationIoctl )
  54. #pragma alloc_text( PAGE, UcReceiveResponseIoctl )
  55. #pragma alloc_text( PAGEUC, UcSendEntityBodyIoctl )
  56. #pragma alloc_text( PAGEUC, UcSendRequestIoctl )
  57. #pragma alloc_text( PAGEUC, UcCancelRequestIoctl )
  58. #endif // ALLOC_PRAGMA
  59. #if 0
  60. NOT PAGEABLE -- UlShutdownAppPoolIoctl
  61. NOT PAGEABLE -- UlpRestartSendHttpResponse
  62. NOT PAGEABLE -- UlShutdownFilterIoctl
  63. #endif
  64. //
  65. // Public functions.
  66. //
  67. /***************************************************************************++
  68. Routine Description:
  69. This routine queries information associated with a control channel.
  70. Note: This is a METHOD_OUT_DIRECT IOCTL.
  71. Arguments:
  72. pIrp - Supplies a pointer to the IO request packet.
  73. pIrpSp - Supplies a pointer to the IO stack location to use for this
  74. request.
  75. Return Value:
  76. NTSTATUS - Completion status.
  77. --***************************************************************************/
  78. NTSTATUS
  79. UlQueryControlChannelIoctl(
  80. IN PIRP pIrp,
  81. IN PIO_STACK_LOCATION pIrpSp
  82. )
  83. {
  84. NTSTATUS Status = STATUS_SUCCESS;
  85. PHTTP_CONTROL_CHANNEL_INFO pInfo;
  86. PUL_CONTROL_CHANNEL pControlChannel;
  87. PVOID pMdlBuffer = NULL;
  88. ULONG Length = 0;
  89. ULONG OutputBufferLength;
  90. //
  91. // sanity check.
  92. //
  93. ASSERT_IOCTL_METHOD(OUT_DIRECT, QUERY_CONTROL_CHANNEL);
  94. PAGED_CODE();
  95. VALIDATE_CONTROL_CHANNEL(pIrpSp, pControlChannel);
  96. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp, HTTP_CONTROL_CHANNEL_INFO, pInfo);
  97. //
  98. // Validate input buffer
  99. // A NULL MdlAddress inidicates a request for buffer length
  100. //
  101. if ( NULL != pIrp->MdlAddress )
  102. {
  103. GET_OUTPUT_BUFFER_ADDRESS_FROM_MDL(pIrp, pMdlBuffer);
  104. }
  105. // Also make sure that user buffer was aligned properly
  106. switch (pInfo->InformationClass)
  107. {
  108. case HttpControlChannelStateInformation:
  109. HANDLE_BUFFER_LENGTH_REQUEST(pIrp, pIrpSp, HTTP_ENABLED_STATE);
  110. VALIDATE_BUFFER_ALIGNMENT(pMdlBuffer, HTTP_ENABLED_STATE);
  111. break;
  112. case HttpControlChannelBandwidthInformation:
  113. HANDLE_BUFFER_LENGTH_REQUEST(pIrp, pIrpSp, HTTP_BANDWIDTH_LIMIT);
  114. VALIDATE_BUFFER_ALIGNMENT(pMdlBuffer, HTTP_BANDWIDTH_LIMIT);
  115. break;
  116. case HttpControlChannelConnectionInformation:
  117. HANDLE_BUFFER_LENGTH_REQUEST(pIrp, pIrpSp, HTTP_CONNECTION_LIMIT);
  118. VALIDATE_BUFFER_ALIGNMENT(pMdlBuffer, HTTP_CONNECTION_LIMIT);
  119. break;
  120. default:
  121. Status = STATUS_INVALID_PARAMETER;
  122. goto end;
  123. break;
  124. }
  125. OutputBufferLength = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  126. Status = UlGetControlChannelInformation(
  127. pIrp->RequestorMode,
  128. pControlChannel,
  129. pInfo->InformationClass,
  130. pMdlBuffer,
  131. OutputBufferLength,
  132. &Length
  133. );
  134. if (NT_SUCCESS(Status))
  135. {
  136. pIrp->IoStatus.Information = (ULONG_PTR)Length;
  137. }
  138. end:
  139. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  140. } // UlQueryControlChannelIoctl
  141. /***************************************************************************++
  142. Routine Description:
  143. This routine sets information associated with a control channel.
  144. Note: This is a METHOD_IN_DIRECT IOCTL.
  145. Arguments:
  146. pIrp - Supplies a pointer to the IO request packet.
  147. pIrpSp - Supplies a pointer to the IO stack location to use for this
  148. request.
  149. Return Value:
  150. NTSTATUS - Completion status.
  151. --***************************************************************************/
  152. NTSTATUS
  153. UlSetControlChannelIoctl(
  154. IN PIRP pIrp,
  155. IN PIO_STACK_LOCATION pIrpSp
  156. )
  157. {
  158. NTSTATUS Status = STATUS_SUCCESS;
  159. PHTTP_CONTROL_CHANNEL_INFO pInfo;
  160. PUL_CONTROL_CHANNEL pControlChannel;
  161. HTTP_CONTROL_CHANNEL_INFORMATION_CLASS Class;
  162. PVOID pMdlBuffer = NULL;
  163. ULONG OutputBufferLength;
  164. //
  165. // sanity check.
  166. //
  167. ASSERT_IOCTL_METHOD(IN_DIRECT, SET_CONTROL_CHANNEL);
  168. PAGED_CODE();
  169. VALIDATE_CONTROL_CHANNEL(pIrpSp, pControlChannel);
  170. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp, HTTP_CONTROL_CHANNEL_INFO, pInfo);
  171. VALIDATE_INFORMATION_CLASS(
  172. pInfo,
  173. Class,
  174. HTTP_CONTROL_CHANNEL_INFORMATION_CLASS,
  175. HttpControlChannelMaximumInformation);
  176. //
  177. // Validate input buffer
  178. //
  179. GET_OUTPUT_BUFFER_ADDRESS_FROM_MDL(pIrp, pMdlBuffer);
  180. switch ( Class )
  181. {
  182. case HttpControlChannelStateInformation:
  183. VALIDATE_OUTPUT_BUFFER_FROM_MDL(
  184. pIrpSp,
  185. pMdlBuffer,
  186. HTTP_ENABLED_STATE);
  187. break;
  188. case HttpControlChannelBandwidthInformation:
  189. VALIDATE_OUTPUT_BUFFER_FROM_MDL(
  190. pIrpSp,
  191. pMdlBuffer,
  192. HTTP_BANDWIDTH_LIMIT);
  193. break;
  194. case HttpControlChannelFilterInformation:
  195. VALIDATE_OUTPUT_BUFFER_FROM_MDL(
  196. pIrpSp,
  197. pMdlBuffer,
  198. HTTP_CONTROL_CHANNEL_FILTER);
  199. break;
  200. case HttpControlChannelTimeoutInformation:
  201. VALIDATE_OUTPUT_BUFFER_FROM_MDL(
  202. pIrpSp,
  203. pMdlBuffer,
  204. HTTP_CONTROL_CHANNEL_TIMEOUT_LIMIT);
  205. break;
  206. case HttpControlChannelUTF8Logging:
  207. VALIDATE_OUTPUT_BUFFER_FROM_MDL(
  208. pIrpSp,
  209. pMdlBuffer,
  210. HTTP_CONTROL_CHANNEL_UTF8_LOGGING);
  211. break;
  212. case HttpControlChannelBinaryLogging:
  213. VALIDATE_OUTPUT_BUFFER_FROM_MDL(
  214. pIrpSp,
  215. pMdlBuffer,
  216. HTTP_CONTROL_CHANNEL_BINARY_LOGGING);
  217. break;
  218. case HttpControlChannelDemandStartThreshold:
  219. VALIDATE_OUTPUT_BUFFER_FROM_MDL(
  220. pIrpSp,
  221. pMdlBuffer,
  222. HTTP_CONTROL_CHANNEL_DEMAND_START_THRESHOLD);
  223. break;
  224. default:
  225. Status = STATUS_INVALID_PARAMETER;
  226. goto end;
  227. break;
  228. }
  229. //
  230. // call the function
  231. //
  232. OutputBufferLength = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  233. Status = UlSetControlChannelInformation(
  234. pControlChannel,
  235. pInfo->InformationClass,
  236. pMdlBuffer,
  237. OutputBufferLength,
  238. pIrp->RequestorMode
  239. );
  240. end:
  241. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  242. } // UlSetControlChannelIoctl
  243. /***************************************************************************++
  244. Routine Description:
  245. This routine creates a new configuration group.
  246. Note: This is a METHOD_BUFFERED IOCTL.
  247. Arguments:
  248. pIrp - Supplies a pointer to the IO request packet.
  249. pIrpSp - Supplies a pointer to the IO stack location to use for this
  250. request.
  251. Return Value:
  252. NTSTATUS - Completion status.
  253. --***************************************************************************/
  254. NTSTATUS
  255. UlCreateConfigGroupIoctl(
  256. IN PIRP pIrp,
  257. IN PIO_STACK_LOCATION pIrpSp
  258. )
  259. {
  260. NTSTATUS Status;
  261. PHTTP_CONFIG_GROUP_INFO pInfo;
  262. PUL_CONTROL_CHANNEL pControlChannel;
  263. HTTP_CONFIG_GROUP_ID LocalConfigGroupId;
  264. //
  265. // sanity check.
  266. //
  267. ASSERT_IOCTL_METHOD(BUFFERED, CREATE_CONFIG_GROUP);
  268. PAGED_CODE();
  269. HTTP_SET_NULL_ID(&LocalConfigGroupId);
  270. VALIDATE_CONTROL_CHANNEL(pIrpSp, pControlChannel);
  271. VALIDATE_OUTPUT_BUFFER(pIrp, pIrpSp,
  272. HTTP_CONFIG_GROUP_INFO, pInfo);
  273. // it's pure output, wipe it to be sure
  274. RtlZeroMemory(pInfo, sizeof(HTTP_CONFIG_GROUP_INFO));
  275. // Call the internal worker func
  276. //
  277. Status = UlCreateConfigGroup(
  278. pControlChannel,
  279. &LocalConfigGroupId
  280. );
  281. if (NT_SUCCESS(Status))
  282. pInfo->ConfigGroupId = LocalConfigGroupId;
  283. end:
  284. if (Status != STATUS_PENDING)
  285. {
  286. // how much output should we return?
  287. pIrp->IoStatus.Information = sizeof(HTTP_CONFIG_GROUP_INFO);
  288. }
  289. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  290. } // UlCreateConfigGroupIoctl
  291. /***************************************************************************++
  292. Routine Description:
  293. This routine deletes an existing configuration group.
  294. Note: This is a METHOD_BUFFERED IOCTL.
  295. Arguments:
  296. pIrp - Supplies a pointer to the IO request packet.
  297. pIrpSp - Supplies a pointer to the IO stack location to use for this
  298. request.
  299. Return Value:
  300. NTSTATUS - Completion status.
  301. --***************************************************************************/
  302. NTSTATUS
  303. UlDeleteConfigGroupIoctl(
  304. IN PIRP pIrp,
  305. IN PIO_STACK_LOCATION pIrpSp
  306. )
  307. {
  308. NTSTATUS Status;
  309. PHTTP_CONFIG_GROUP_INFO pInfo;
  310. PUL_CONTROL_CHANNEL pControlChannel;
  311. //
  312. // sanity check.
  313. //
  314. ASSERT_IOCTL_METHOD(BUFFERED, DELETE_CONFIG_GROUP);
  315. PAGED_CODE();
  316. VALIDATE_CONTROL_CHANNEL(pIrpSp, pControlChannel);
  317. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp, HTTP_CONFIG_GROUP_INFO, pInfo);
  318. Status = UlDeleteConfigGroup(pInfo->ConfigGroupId);
  319. end:
  320. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  321. } // UlDeleteConfigGroupIoctl
  322. /***************************************************************************++
  323. Routine Description:
  324. This routine queries information associated with a configuration group.
  325. Note: This is a METHOD_OUT_DIRECT IOCTL.
  326. Arguments:
  327. pIrp - Supplies a pointer to the IO request packet.
  328. pIrpSp - Supplies a pointer to the IO stack location to use for this
  329. request.
  330. Return Value:
  331. NTSTATUS - Completion status.
  332. --***************************************************************************/
  333. NTSTATUS
  334. UlQueryConfigGroupIoctl(
  335. IN PIRP pIrp,
  336. IN PIO_STACK_LOCATION pIrpSp
  337. )
  338. {
  339. NTSTATUS Status = STATUS_SUCCESS;
  340. PHTTP_CONFIG_GROUP_INFO pInfo;
  341. PVOID pMdlBuffer = NULL;
  342. ULONG Length = 0L;
  343. ULONG OutputLength;
  344. PUL_CONTROL_CHANNEL pControlChannel;
  345. HTTP_CONFIG_GROUP_INFORMATION_CLASS Class;
  346. //
  347. // sanity check.
  348. //
  349. ASSERT_IOCTL_METHOD(OUT_DIRECT, QUERY_CONFIG_GROUP);
  350. PAGED_CODE();
  351. //
  352. // Going to access the url string from user mode memory
  353. //
  354. VALIDATE_CONTROL_CHANNEL(pIrpSp, pControlChannel);
  355. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp, HTTP_CONFIG_GROUP_INFO, pInfo);
  356. VALIDATE_INFORMATION_CLASS(
  357. pInfo,
  358. Class,
  359. HTTP_CONFIG_GROUP_INFORMATION_CLASS,
  360. HttpConfigGroupMaximumInformation);
  361. //
  362. // Validate input buffer
  363. // A NULL MdlAddress inidicates a request for buffer length
  364. //
  365. if ( NULL != pIrp->MdlAddress )
  366. {
  367. GET_OUTPUT_BUFFER_ADDRESS_FROM_MDL(pIrp, pMdlBuffer);
  368. }
  369. switch ( Class )
  370. {
  371. case HttpConfigGroupBandwidthInformation:
  372. HANDLE_BUFFER_LENGTH_REQUEST(
  373. pIrp,
  374. pIrpSp,
  375. HTTP_CONFIG_GROUP_MAX_BANDWIDTH);
  376. VALIDATE_BUFFER_ALIGNMENT(
  377. pMdlBuffer,
  378. HTTP_CONFIG_GROUP_MAX_BANDWIDTH);
  379. break;
  380. case HttpConfigGroupConnectionInformation:
  381. HANDLE_BUFFER_LENGTH_REQUEST(
  382. pIrp,
  383. pIrpSp,
  384. HTTP_CONFIG_GROUP_MAX_CONNECTIONS);
  385. VALIDATE_BUFFER_ALIGNMENT(
  386. pMdlBuffer,
  387. HTTP_CONFIG_GROUP_MAX_CONNECTIONS);
  388. break;
  389. case HttpConfigGroupStateInformation:
  390. HANDLE_BUFFER_LENGTH_REQUEST(
  391. pIrp,
  392. pIrpSp,
  393. HTTP_CONFIG_GROUP_STATE);
  394. VALIDATE_BUFFER_ALIGNMENT(
  395. pMdlBuffer,
  396. HTTP_CONFIG_GROUP_STATE);
  397. break;
  398. case HttpConfigGroupConnectionTimeoutInformation:
  399. HANDLE_BUFFER_LENGTH_REQUEST(pIrp, pIrpSp, ULONG);
  400. VALIDATE_BUFFER_ALIGNMENT(pMdlBuffer, ULONG);
  401. break;
  402. case HttpConfigGroupAppPoolInformation:
  403. default:
  404. Status = STATUS_INVALID_PARAMETER;
  405. goto end;
  406. break;
  407. }
  408. //
  409. // call the function
  410. //
  411. OutputLength = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  412. Status = UlQueryConfigGroupInformation(
  413. pInfo->ConfigGroupId,
  414. pInfo->InformationClass,
  415. pMdlBuffer,
  416. OutputLength,
  417. &Length
  418. );
  419. pIrp->IoStatus.Information = (NT_SUCCESS(Status)) ?
  420. (ULONG_PTR)Length : (ULONG_PTR)0;
  421. end:
  422. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  423. } // UlQueryConfigGroupIoctl
  424. /***************************************************************************++
  425. Routine Description:
  426. This routine sets information associated with a configuration group.
  427. Note: This is a METHOD_IN_DIRECT IOCTL.
  428. Arguments:
  429. pIrp - Supplies a pointer to the IO request packet.
  430. pIrpSp - Supplies a pointer to the IO stack location to use for this
  431. request.
  432. Return Value:
  433. NTSTATUS - Completion status.
  434. --***************************************************************************/
  435. NTSTATUS
  436. UlSetConfigGroupIoctl(
  437. IN PIRP pIrp,
  438. IN PIO_STACK_LOCATION pIrpSp
  439. )
  440. {
  441. NTSTATUS Status;
  442. PHTTP_CONFIG_GROUP_INFO pInfo;
  443. PVOID pMdlBuffer;
  444. ULONG OutputLength;
  445. PUL_CONTROL_CHANNEL pControlChannel;
  446. HTTP_CONFIG_GROUP_INFORMATION_CLASS Class;
  447. //
  448. // sanity check.
  449. //
  450. ASSERT_IOCTL_METHOD(IN_DIRECT, SET_CONFIG_GROUP);
  451. PAGED_CODE();
  452. VALIDATE_CONTROL_CHANNEL(pIrpSp, pControlChannel);
  453. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp, HTTP_CONFIG_GROUP_INFO, pInfo);
  454. VALIDATE_INFORMATION_CLASS(
  455. pInfo,
  456. Class,
  457. HTTP_CONFIG_GROUP_INFORMATION_CLASS,
  458. HttpConfigGroupMaximumInformation);
  459. //
  460. // Validate input buffer
  461. //
  462. GET_OUTPUT_BUFFER_ADDRESS_FROM_MDL(pIrp, pMdlBuffer);
  463. switch ( Class )
  464. {
  465. case HttpConfigGroupLogInformation:
  466. VALIDATE_OUTPUT_BUFFER_FROM_MDL(
  467. pIrpSp,
  468. pMdlBuffer,
  469. HTTP_CONFIG_GROUP_LOGGING);
  470. break;
  471. case HttpConfigGroupAppPoolInformation:
  472. VALIDATE_OUTPUT_BUFFER_FROM_MDL(
  473. pIrpSp,
  474. pMdlBuffer,
  475. HTTP_CONFIG_GROUP_APP_POOL);
  476. break;
  477. case HttpConfigGroupBandwidthInformation:
  478. VALIDATE_OUTPUT_BUFFER_FROM_MDL(
  479. pIrpSp,
  480. pMdlBuffer,
  481. HTTP_CONFIG_GROUP_MAX_BANDWIDTH);
  482. break;
  483. case HttpConfigGroupConnectionInformation:
  484. VALIDATE_OUTPUT_BUFFER_FROM_MDL(
  485. pIrpSp,
  486. pMdlBuffer,
  487. HTTP_CONFIG_GROUP_MAX_CONNECTIONS);
  488. break;
  489. case HttpConfigGroupStateInformation:
  490. VALIDATE_OUTPUT_BUFFER_FROM_MDL(
  491. pIrpSp,
  492. pMdlBuffer,
  493. HTTP_CONFIG_GROUP_STATE);
  494. break;
  495. case HttpConfigGroupSiteInformation:
  496. VALIDATE_OUTPUT_BUFFER_FROM_MDL(
  497. pIrpSp,
  498. pMdlBuffer,
  499. HTTP_CONFIG_GROUP_SITE);
  500. break;
  501. case HttpConfigGroupConnectionTimeoutInformation:
  502. VALIDATE_OUTPUT_BUFFER_FROM_MDL(
  503. pIrpSp,
  504. pMdlBuffer,
  505. ULONG);
  506. break;
  507. default:
  508. Status = STATUS_INVALID_PARAMETER;
  509. goto end;
  510. break;
  511. }
  512. //
  513. // call the function
  514. //
  515. OutputLength = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  516. UlTrace(IOCTL,
  517. ("UlSetConfigGroupIoctl: CGroupId=%I64x, "
  518. "InfoClass=%d, pMdlBuffer=%p, length=%d\n",
  519. pInfo->ConfigGroupId,
  520. pInfo->InformationClass,
  521. pMdlBuffer,
  522. OutputLength
  523. ));
  524. Status = UlSetConfigGroupInformation(
  525. pInfo->ConfigGroupId,
  526. pInfo->InformationClass,
  527. pMdlBuffer,
  528. OutputLength,
  529. pIrp->RequestorMode
  530. );
  531. end:
  532. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  533. } // UlSetConfigGroupIoctl
  534. /***************************************************************************++
  535. Routine Description:
  536. This routine adds a new URL prefix to a configuration group.
  537. Note: This is a METHOD_BUFFERED IOCTL.
  538. Arguments:
  539. pIrp - Supplies a pointer to the IO request packet.
  540. pIrpSp - Supplies a pointer to the IO stack location to use for this
  541. request.
  542. Return Value:
  543. NTSTATUS - Completion status.
  544. --***************************************************************************/
  545. NTSTATUS
  546. UlAddUrlToConfigGroupIoctl(
  547. IN PIRP pIrp,
  548. IN PIO_STACK_LOCATION pIrpSp
  549. )
  550. {
  551. NTSTATUS Status;
  552. PHTTP_CONFIG_GROUP_URL_INFO pInfo;
  553. PUL_CONTROL_CHANNEL pControlChannel;
  554. UNICODE_STRING FullyQualifiedUrl;
  555. ACCESS_STATE AccessState;
  556. AUX_ACCESS_DATA AuxData;
  557. ACCESS_MASK AccessMask;
  558. //
  559. // sanity check.
  560. //
  561. ASSERT_IOCTL_METHOD(BUFFERED, ADD_URL_TO_CONFIG_GROUP);
  562. PAGED_CODE();
  563. RtlInitEmptyUnicodeString(&FullyQualifiedUrl, NULL, 0);
  564. VALIDATE_CONTROL_CHANNEL(pIrpSp, pControlChannel);
  565. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp, HTTP_CONFIG_GROUP_URL_INFO, pInfo);
  566. __try
  567. {
  568. Status =
  569. UlProbeAndCaptureUnicodeString(
  570. &pInfo->FullyQualifiedUrl,
  571. pIrp->RequestorMode,
  572. &FullyQualifiedUrl,
  573. UNICODE_STRING_MAX_WCHAR_LEN
  574. );
  575. }
  576. __except( UL_EXCEPTION_FILTER() )
  577. {
  578. Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode());
  579. }
  580. if (NT_SUCCESS(Status))
  581. {
  582. //
  583. // Validate type of operation being performed.
  584. //
  585. if (pInfo->UrlType != HttpUrlOperatorTypeRegistration &&
  586. pInfo->UrlType != HttpUrlOperatorTypeReservation)
  587. {
  588. Status = STATUS_INVALID_PARAMETER;
  589. goto end;
  590. }
  591. //
  592. // Set Access mask.
  593. //
  594. AccessMask = (pInfo->UrlType == HttpUrlOperatorTypeRegistration)?
  595. HTTP_ALLOW_REGISTER_URL : HTTP_ALLOW_DELEGATE_URL;
  596. //
  597. // Capture the thread's access state. Adding a reservation is
  598. // delegation.
  599. //
  600. Status = SeCreateAccessState(
  601. &AccessState,
  602. &AuxData,
  603. AccessMask,
  604. &g_UrlAccessGenericMapping
  605. );
  606. if (NT_SUCCESS(Status))
  607. {
  608. Status = UlAddUrlToConfigGroup(
  609. pInfo,
  610. &FullyQualifiedUrl,
  611. &AccessState,
  612. AccessMask,
  613. pIrp->RequestorMode
  614. );
  615. //
  616. // Delete the access state created above.
  617. //
  618. SeDeleteAccessState(&AccessState);
  619. }
  620. }
  621. end:
  622. UlFreeCapturedUnicodeString(&FullyQualifiedUrl);
  623. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  624. }
  625. /***************************************************************************++
  626. Routine Description:
  627. This routine removes a URL prefix from a configuration group.
  628. Note: This is a METHOD_BUFFERED IOCTL.
  629. Arguments:
  630. pIrp - Supplies a pointer to the IO request packet.
  631. pIrpSp - Supplies a pointer to the IO stack location to use for this
  632. request.
  633. Return Value:
  634. NTSTATUS - Completion status.
  635. --***************************************************************************/
  636. NTSTATUS
  637. UlRemoveUrlFromConfigGroupIoctl(
  638. IN PIRP pIrp,
  639. IN PIO_STACK_LOCATION pIrpSp
  640. )
  641. {
  642. NTSTATUS Status;
  643. PHTTP_CONFIG_GROUP_URL_INFO pInfo;
  644. PUL_CONTROL_CHANNEL pControlChannel;
  645. UNICODE_STRING FullyQualifiedUrl;
  646. ACCESS_STATE AccessState;
  647. AUX_ACCESS_DATA AuxData;
  648. //
  649. // sanity check.
  650. //
  651. ASSERT_IOCTL_METHOD(BUFFERED, REMOVE_URL_FROM_CONFIG_GROUP);
  652. PAGED_CODE();
  653. RtlInitEmptyUnicodeString(&FullyQualifiedUrl, NULL, 0);
  654. VALIDATE_CONTROL_CHANNEL(pIrpSp, pControlChannel);
  655. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp, HTTP_CONFIG_GROUP_URL_INFO, pInfo);
  656. __try
  657. {
  658. Status =
  659. UlProbeAndCaptureUnicodeString(
  660. &pInfo->FullyQualifiedUrl,
  661. pIrp->RequestorMode,
  662. &FullyQualifiedUrl,
  663. UNICODE_STRING_MAX_WCHAR_LEN
  664. );
  665. }
  666. __except( UL_EXCEPTION_FILTER() )
  667. {
  668. Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode());
  669. }
  670. if(NT_SUCCESS(Status))
  671. {
  672. //
  673. // Validate type of operation being performed.
  674. //
  675. if (pInfo->UrlType != HttpUrlOperatorTypeRegistration &&
  676. pInfo->UrlType != HttpUrlOperatorTypeReservation)
  677. {
  678. Status = STATUS_INVALID_PARAMETER;
  679. goto end;
  680. }
  681. //
  682. // Capture the thread's access state. Removing a reservation is
  683. // same as delegation.
  684. //
  685. Status = SeCreateAccessState(
  686. &AccessState,
  687. &AuxData,
  688. HTTP_ALLOW_DELEGATE_URL,
  689. &g_UrlAccessGenericMapping
  690. );
  691. if (NT_SUCCESS(Status))
  692. {
  693. //
  694. // Further sanitization and stronger checks will happen in cgroup.
  695. //
  696. Status = UlRemoveUrlFromConfigGroup(
  697. pInfo,
  698. &FullyQualifiedUrl,
  699. &AccessState,
  700. HTTP_ALLOW_DELEGATE_URL,
  701. pIrp->RequestorMode
  702. );
  703. //
  704. // Delete the above captured state.
  705. //
  706. SeDeleteAccessState(&AccessState);
  707. }
  708. }
  709. end:
  710. UlFreeCapturedUnicodeString(&FullyQualifiedUrl);
  711. COMPLETE_REQUEST_AND_RETURN(pIrp, Status);
  712. }
  713. /***************************************************************************++
  714. Routine Description:
  715. This routine removes all URLs from a configuration group.
  716. Note: This is a METHOD_BUFFERED IOCTL.
  717. Arguments:
  718. pIrp - Supplies a pointer to the IO request packet.
  719. pIrpSp - Supplies a pointer to the IO stack location to use for this
  720. request.
  721. Return Value:
  722. NTSTATUS - Completion status.
  723. --***************************************************************************/
  724. NTSTATUS
  725. UlRemoveAllUrlsFromConfigGroupIoctl(
  726. IN PIRP pIrp,
  727. IN PIO_STACK_LOCATION pIrpSp
  728. )
  729. {
  730. NTSTATUS Status;
  731. PHTTP_REMOVE_ALL_URLS_INFO pInfo;
  732. PUL_CONTROL_CHANNEL pControlChannel;
  733. //
  734. // Sanity check.
  735. //
  736. ASSERT_IOCTL_METHOD(BUFFERED, REMOVE_ALL_URLS_FROM_CONFIG_GROUP);
  737. PAGED_CODE();
  738. VALIDATE_CONTROL_CHANNEL(pIrpSp, pControlChannel);
  739. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp, HTTP_REMOVE_ALL_URLS_INFO, pInfo);
  740. //
  741. // Call the internal worker function.
  742. //
  743. Status = UlRemoveAllUrlsFromConfigGroup( pInfo->ConfigGroupId );
  744. end:
  745. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  746. }
  747. /***************************************************************************++
  748. Routine Description:
  749. This routine queries information associated with an application pool.
  750. Note: This is a METHOD_OUT_DIRECT IOCTL.
  751. Arguments:
  752. pIrp - Supplies a pointer to the IO request packet.
  753. pIrpSp - Supplies a pointer to the IO stack location to use for this
  754. request.
  755. Return Value:
  756. NTSTATUS - Completion status.
  757. --***************************************************************************/
  758. NTSTATUS
  759. UlQueryAppPoolInformationIoctl(
  760. IN PIRP pIrp,
  761. IN PIO_STACK_LOCATION pIrpSp
  762. )
  763. {
  764. NTSTATUS Status = STATUS_SUCCESS;
  765. PHTTP_APP_POOL_INFO pInfo;
  766. PVOID pMdlBuffer = NULL;
  767. ULONG OutputBufferLength;
  768. ULONG Length = 0;
  769. PUL_APP_POOL_PROCESS pProcess;
  770. HTTP_APP_POOL_INFORMATION_CLASS Class;
  771. //
  772. // sanity check.
  773. //
  774. ASSERT_IOCTL_METHOD(OUT_DIRECT, QUERY_APP_POOL_INFORMATION);
  775. PAGED_CODE();
  776. // pProcess is an aligned address because it is allocated
  777. // by the I/O Manager.
  778. VALIDATE_APP_POOL(pIrpSp, pProcess, FALSE);
  779. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp, HTTP_APP_POOL_INFO, pInfo);
  780. VALIDATE_INFORMATION_CLASS(
  781. pInfo,
  782. Class,
  783. HTTP_APP_POOL_INFORMATION_CLASS,
  784. HttpConfigGroupMaximumInformation);
  785. // if no outbut buffer passed down in the Irp
  786. // that means app is asking for the required
  787. // field length
  788. if ( NULL != pIrp->MdlAddress )
  789. {
  790. GET_OUTPUT_BUFFER_ADDRESS_FROM_MDL(pIrp, pMdlBuffer);
  791. }
  792. // Verify input data in output buffer
  793. switch ( Class )
  794. {
  795. case HttpAppPoolQueueLengthInformation:
  796. HANDLE_BUFFER_LENGTH_REQUEST(
  797. pIrp,
  798. pIrpSp,
  799. LONG);
  800. VALIDATE_BUFFER_ALIGNMENT(
  801. pMdlBuffer,
  802. LONG);
  803. break;
  804. case HttpAppPoolStateInformation:
  805. HANDLE_BUFFER_LENGTH_REQUEST(
  806. pIrp,
  807. pIrpSp,
  808. HTTP_APP_POOL_ENABLED_STATE);
  809. VALIDATE_BUFFER_ALIGNMENT(
  810. pMdlBuffer,
  811. HTTP_APP_POOL_ENABLED_STATE);
  812. break;
  813. case HttpAppPoolLoadBalancerInformation:
  814. HANDLE_BUFFER_LENGTH_REQUEST(
  815. pIrp,
  816. pIrpSp,
  817. HTTP_LOAD_BALANCER_CAPABILITIES);
  818. VALIDATE_BUFFER_ALIGNMENT(
  819. pMdlBuffer,
  820. HTTP_LOAD_BALANCER_CAPABILITIES);
  821. break;
  822. default:
  823. Status = STATUS_INVALID_PARAMETER;
  824. goto end;
  825. break;
  826. }
  827. OutputBufferLength = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  828. Status = UlQueryAppPoolInformation(
  829. pProcess,
  830. pInfo->InformationClass,
  831. pMdlBuffer,
  832. OutputBufferLength,
  833. &Length
  834. );
  835. pIrp->IoStatus.Information = (NT_SUCCESS(Status)) ?
  836. (ULONG_PTR)Length : (ULONG_PTR)0;
  837. end:
  838. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  839. } // UlQueryAppPoolInformationIoctl
  840. /***************************************************************************++
  841. Routine Description:
  842. This routine sets information associated with an application pool.
  843. Note: This is a METHOD_IN_DIRECT IOCTL.
  844. Arguments:
  845. pIrp - Supplies a pointer to the IO request packet.
  846. pIrpSp - Supplies a pointer to the IO stack location to use for this
  847. request.
  848. Return Value:
  849. NTSTATUS - Completion status.
  850. --***************************************************************************/
  851. NTSTATUS
  852. UlSetAppPoolInformationIoctl(
  853. IN PIRP pIrp,
  854. IN PIO_STACK_LOCATION pIrpSp
  855. )
  856. {
  857. NTSTATUS Status = STATUS_SUCCESS;
  858. PHTTP_APP_POOL_INFO pInfo;
  859. PVOID pMdlBuffer = NULL;
  860. PUL_APP_POOL_PROCESS pProcess = NULL;
  861. ULONG OutputBufferLength;
  862. HTTP_APP_POOL_INFORMATION_CLASS Class;
  863. //
  864. // Sanity check
  865. //
  866. ASSERT_IOCTL_METHOD(IN_DIRECT, SET_APP_POOL_INFORMATION);
  867. PAGED_CODE();
  868. VALIDATE_APP_POOL(pIrpSp, pProcess, FALSE);
  869. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp, HTTP_APP_POOL_INFO, pInfo);
  870. VALIDATE_INFORMATION_CLASS(
  871. pInfo,
  872. Class,
  873. HTTP_APP_POOL_INFORMATION_CLASS,
  874. HttpConfigGroupMaximumInformation);
  875. //
  876. // Validate input buffer
  877. //
  878. GET_OUTPUT_BUFFER_ADDRESS_FROM_MDL(pIrp, pMdlBuffer);
  879. //
  880. // Also make sure that user buffer was aligned properly
  881. //
  882. switch (pInfo->InformationClass)
  883. {
  884. case HttpAppPoolQueueLengthInformation:
  885. VALIDATE_OUTPUT_BUFFER_FROM_MDL(
  886. pIrpSp,
  887. pMdlBuffer,
  888. LONG);
  889. break;
  890. case HttpAppPoolStateInformation:
  891. VALIDATE_OUTPUT_BUFFER_FROM_MDL(
  892. pIrpSp,
  893. pMdlBuffer,
  894. HTTP_APP_POOL_ENABLED_STATE);
  895. break;
  896. case HttpAppPoolLoadBalancerInformation:
  897. VALIDATE_OUTPUT_BUFFER_FROM_MDL(
  898. pIrpSp,
  899. pMdlBuffer,
  900. HTTP_LOAD_BALANCER_CAPABILITIES);
  901. break;
  902. case HttpAppPoolControlChannelInformation:
  903. VALIDATE_OUTPUT_BUFFER_FROM_MDL(
  904. pIrpSp,
  905. pMdlBuffer,
  906. HTTP_APP_POOL_CONTROL_CHANNEL);
  907. break;
  908. default:
  909. Status = STATUS_INVALID_PARAMETER;
  910. goto end;
  911. break;
  912. }
  913. OutputBufferLength = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  914. Status = UlSetAppPoolInformation(
  915. pProcess,
  916. pInfo->InformationClass,
  917. pMdlBuffer,
  918. OutputBufferLength
  919. );
  920. end:
  921. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  922. } // UlSetAppPoolInformationIoctl
  923. /***************************************************************************++
  924. Routine Description:
  925. This routine stops request processing on the app pool and cancels
  926. outstanding I/O.
  927. Note: This is a METHOD_BUFFERED IOCTL.
  928. Arguments:
  929. pIrp - Supplies a pointer to the IO request packet.
  930. pIrpSp - Supplies a pointer to the IO stack location to use for this
  931. request.
  932. Return Value:
  933. NTSTATUS - Completion status.
  934. --***************************************************************************/
  935. NTSTATUS
  936. UlShutdownAppPoolIoctl(
  937. IN PIRP pIrp,
  938. IN PIO_STACK_LOCATION pIrpSp
  939. )
  940. {
  941. NTSTATUS Status = STATUS_SUCCESS;
  942. PUL_APP_POOL_PROCESS pProcess;
  943. //
  944. // sanity check.
  945. //
  946. ASSERT_IOCTL_METHOD(BUFFERED, SHUTDOWN_APP_POOL);
  947. PAGED_CODE();
  948. VALIDATE_APP_POOL(pIrpSp, pProcess, FALSE);
  949. //
  950. // make the call
  951. //
  952. UlTrace(IOCTL,
  953. ("UlShutdownAppPoolIoctl: pAppPoolProcess=%p, pIrp=%p\n",
  954. pProcess,
  955. pIrp
  956. ));
  957. UlShutdownAppPoolProcess(
  958. pProcess
  959. );
  960. Status = STATUS_SUCCESS;
  961. end:
  962. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  963. } // UlShutdownAppPoolIoctl
  964. /***************************************************************************++
  965. Routine Description:
  966. This routine receives an HTTP request.
  967. Note: This is a METHOD_OUT_DIRECT IOCTL.
  968. Arguments:
  969. pIrp - Supplies a pointer to the IO request packet.
  970. pIrpSp - Supplies a pointer to the IO stack location to use for this
  971. request.
  972. Return Value:
  973. NTSTATUS - Completion status.
  974. --***************************************************************************/
  975. NTSTATUS
  976. UlReceiveHttpRequestIoctl(
  977. IN PIRP pIrp,
  978. IN PIO_STACK_LOCATION pIrpSp
  979. )
  980. {
  981. NTSTATUS Status;
  982. PHTTP_RECEIVE_REQUEST_INFO pInfo;
  983. PUL_APP_POOL_PROCESS pProcess = NULL;
  984. //
  985. // Sanity check.
  986. //
  987. ASSERT_IOCTL_METHOD(OUT_DIRECT, RECEIVE_HTTP_REQUEST);
  988. PAGED_CODE();
  989. VALIDATE_APP_POOL(pIrpSp, pProcess, TRUE);
  990. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp, HTTP_RECEIVE_REQUEST_INFO, pInfo);
  991. VALIDATE_OUTPUT_BUFFER_ADDRESS_FROM_MDL(pIrp, PVOID);
  992. //
  993. // First make sure the output buffer is at least
  994. // minimum size. This is important as we require
  995. // at least this much space later.
  996. //
  997. UlTrace(ROUTING, (
  998. "UlReceiveHttpRequestIoctl(outbuf=%d, inbuf=%d)\n",
  999. pIrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  1000. pIrpSp->Parameters.DeviceIoControl.InputBufferLength
  1001. ));
  1002. if ((pIrpSp->Parameters.DeviceIoControl.OutputBufferLength >=
  1003. sizeof(HTTP_REQUEST)) &&
  1004. (pIrpSp->Parameters.DeviceIoControl.InputBufferLength ==
  1005. sizeof(HTTP_RECEIVE_REQUEST_INFO)))
  1006. {
  1007. if (pInfo->Flags & (~HTTP_RECEIVE_REQUEST_FLAG_VALID))
  1008. {
  1009. Status = STATUS_INVALID_PARAMETER;
  1010. goto end;
  1011. }
  1012. Status = UlReceiveHttpRequest(
  1013. pInfo->RequestId,
  1014. pInfo->Flags,
  1015. pProcess,
  1016. pIrp
  1017. );
  1018. }
  1019. else
  1020. {
  1021. Status = STATUS_BUFFER_TOO_SMALL;
  1022. }
  1023. UlTrace(ROUTING, (
  1024. "UlReceiveHttpRequestIoctl: BytesNeeded=%Iu, status=0x%x\n",
  1025. pIrp->IoStatus.Information, Status
  1026. ));
  1027. end:
  1028. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  1029. } // UlReceiveHttpRequestIoctl
  1030. /***************************************************************************++
  1031. Routine Description:
  1032. This routine receives entity body data from an HTTP request.
  1033. Note: This is a METHOD_OUT_DIRECT IOCTL.
  1034. Arguments:
  1035. pIrp - Supplies a pointer to the IO request packet.
  1036. pIrpSp - Supplies a pointer to the IO stack location to use for this
  1037. request.
  1038. Return Value:
  1039. NTSTATUS - Completion status.
  1040. --***************************************************************************/
  1041. NTSTATUS
  1042. UlReceiveEntityBodyIoctl(
  1043. IN PIRP pIrp,
  1044. IN PIO_STACK_LOCATION pIrpSp
  1045. )
  1046. {
  1047. NTSTATUS Status = STATUS_SUCCESS;
  1048. PHTTP_RECEIVE_REQUEST_INFO pInfo;
  1049. PUL_APP_POOL_PROCESS pProcess;
  1050. PUL_INTERNAL_REQUEST pRequest = NULL;
  1051. //
  1052. // Sanity check.
  1053. //
  1054. ASSERT_IOCTL_METHOD(OUT_DIRECT, RECEIVE_ENTITY_BODY);
  1055. PAGED_CODE();
  1056. VALIDATE_APP_POOL(pIrpSp, pProcess, TRUE);
  1057. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp, HTTP_RECEIVE_REQUEST_INFO, pInfo);
  1058. //
  1059. // Validate output buffer for METHOD_OUT_DIRECT.
  1060. //
  1061. if (NULL == pIrp->MdlAddress)
  1062. {
  1063. Status = STATUS_INVALID_PARAMETER;
  1064. goto end;
  1065. }
  1066. //
  1067. // Now get the request from the request id.
  1068. // This gets us a reference to the request.
  1069. //
  1070. pRequest = UlGetRequestFromId(pInfo->RequestId, pProcess);
  1071. if (!pRequest)
  1072. {
  1073. Status = STATUS_CONNECTION_INVALID;
  1074. goto end;
  1075. }
  1076. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  1077. //
  1078. // OK, now call the function.
  1079. //
  1080. Status = UlReceiveEntityBody(pProcess, pRequest, pIrp);
  1081. end:
  1082. if (pRequest != NULL)
  1083. {
  1084. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  1085. pRequest = NULL;
  1086. }
  1087. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  1088. } // UlReceiveEntityBodyIoctl
  1089. /***************************************************************************++
  1090. Routine Description:
  1091. This routine sends an HTTP response.
  1092. Note: This is a METHOD_NEITHER IOCTL.
  1093. Arguments:
  1094. pIrp - Supplies a pointer to the IO request packet.
  1095. pIrpSp - Supplies a pointer to the IO stack location to use for this
  1096. request.
  1097. Return Value:
  1098. NTSTATUS - Completion status.
  1099. --***************************************************************************/
  1100. NTSTATUS
  1101. UlSendHttpResponseIoctl(
  1102. IN PIRP pIrp,
  1103. IN PIO_STACK_LOCATION pIrpSp
  1104. )
  1105. {
  1106. NTSTATUS Status = STATUS_SUCCESS;
  1107. PHTTP_SEND_HTTP_RESPONSE_INFO pSendInfo;
  1108. HTTP_SEND_HTTP_RESPONSE_INFO LocalSendInfo;
  1109. PUL_INTERNAL_RESPONSE pResponse = NULL;
  1110. PUL_INTERNAL_RESPONSE pResponseCopy;
  1111. PHTTP_RESPONSE pHttpResponse = NULL;
  1112. PUL_INTERNAL_REQUEST pRequest = NULL;
  1113. BOOLEAN ServedFromCache = FALSE;
  1114. BOOLEAN CaptureCache;
  1115. PUL_APP_POOL_PROCESS pAppPoolProcess = NULL;
  1116. ULONG BufferLength = 0;
  1117. BOOLEAN FastSend = FALSE;
  1118. BOOLEAN CopySend = FALSE;
  1119. BOOLEAN CloseConnection = FALSE;
  1120. BOOLEAN LastResponse = FALSE;
  1121. HTTP_REQUEST_ID RequestId = HTTP_NULL_ID;
  1122. HTTP_DATA_CHUNK LocalEntityChunks[UL_LOCAL_CHUNKS];
  1123. PHTTP_DATA_CHUNK pLocalEntityChunks = NULL;
  1124. PHTTP_DATA_CHUNK pEntityChunks;
  1125. HTTP_LOG_FIELDS_DATA LocalLogData;
  1126. USHORT StatusCode = 0;
  1127. ULONGLONG SendBytes = 0;
  1128. ULONGLONG ConnectionSendBytes = 0;
  1129. ULONGLONG GlobalSendBytes = 0;
  1130. //
  1131. // Sanity check.
  1132. //
  1133. ASSERT_IOCTL_METHOD(NEITHER, SEND_HTTP_RESPONSE);
  1134. PAGED_CODE();
  1135. __try
  1136. {
  1137. //
  1138. // Ensure that this is really an app pool, not a control channel.
  1139. // And it's going until we are done with the sendresponse.
  1140. //
  1141. VALIDATE_APP_POOL(pIrpSp, pAppPoolProcess, TRUE);
  1142. VALIDATE_SEND_INFO(
  1143. pIrp,
  1144. pIrpSp,
  1145. pSendInfo,
  1146. LocalSendInfo,
  1147. pEntityChunks,
  1148. pLocalEntityChunks,
  1149. LocalEntityChunks
  1150. );
  1151. VALIDATE_LOG_DATA(pIrp, LocalSendInfo, LocalLogData);
  1152. LastResponse = (BOOLEAN)
  1153. (0 == (LocalSendInfo.Flags & HTTP_SEND_RESPONSE_FLAG_MORE_DATA));
  1154. if (ETW_LOG_MIN() && LastResponse)
  1155. {
  1156. RequestId = LocalSendInfo.RequestId;
  1157. UlEtwTraceEvent(
  1158. &UlTransGuid,
  1159. ETW_TYPE_ULRECV_RESP,
  1160. (PVOID) &RequestId,
  1161. sizeof(HTTP_REQUEST_ID),
  1162. NULL,
  1163. 0
  1164. );
  1165. }
  1166. UlTrace(SEND_RESPONSE, (
  1167. "http!UlSendHttpResponseIoctl - Flags = %X\n",
  1168. LocalSendInfo.Flags
  1169. ));
  1170. //
  1171. // UlSendHttpResponse() *must* take a PHTTP_RESPONSE. This will
  1172. // protect us from those whackos that attempt to build their own
  1173. // raw response headers.
  1174. //
  1175. pHttpResponse = LocalSendInfo.pHttpResponse;
  1176. if (pHttpResponse == NULL)
  1177. {
  1178. Status = STATUS_INVALID_PARAMETER;
  1179. goto end;
  1180. }
  1181. //
  1182. // Now get the request from the request id.
  1183. // This gives us a reference to the request.
  1184. //
  1185. pRequest = UlGetRequestFromId(LocalSendInfo.RequestId, pAppPoolProcess);
  1186. if (pRequest == NULL)
  1187. {
  1188. //
  1189. // Couldn't map the HTTP_REQUEST_ID.
  1190. //
  1191. Status = STATUS_CONNECTION_INVALID;
  1192. goto end;
  1193. }
  1194. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  1195. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pRequest->pHttpConn));
  1196. //
  1197. // OK, we have the connection. Now capture the incoming
  1198. // HTTP_RESPONSE structure and map it to our internal
  1199. // format.
  1200. //
  1201. if (LocalSendInfo.CachePolicy.Policy != HttpCachePolicyNocache)
  1202. {
  1203. CaptureCache = pRequest->CachePreconditions;
  1204. }
  1205. else
  1206. {
  1207. CaptureCache = FALSE;
  1208. }
  1209. //
  1210. // Check if we need to perform a CopySend if this IRP is
  1211. // non-overlapped and this is not LastResponse.
  1212. //
  1213. if (g_UlEnableCopySend &&
  1214. !LastResponse &&
  1215. !pIrp->Overlay.AsynchronousParameters.UserApcRoutine &&
  1216. !pIrp->Overlay.AsynchronousParameters.UserApcContext)
  1217. {
  1218. CopySend = TRUE;
  1219. }
  1220. //
  1221. // Take the fast path if this is a single memory chunk that needs no
  1222. // retransmission (<= 64k).
  1223. //
  1224. if (!CaptureCache && !pRequest->SendInProgress && !CopySend
  1225. && LocalSendInfo.EntityChunkCount == 1
  1226. && pEntityChunks->DataChunkType == HttpDataChunkFromMemory
  1227. && pEntityChunks->FromMemory.BufferLength <= g_UlMaxBytesPerSend)
  1228. {
  1229. BufferLength = pEntityChunks->FromMemory.BufferLength;
  1230. FastSend = (BOOLEAN) (BufferLength > 0);
  1231. }
  1232. if (!FastSend)
  1233. {
  1234. Status = UlCaptureHttpResponse(
  1235. pAppPoolProcess,
  1236. LocalSendInfo.pHttpResponse,
  1237. pRequest,
  1238. LocalSendInfo.EntityChunkCount,
  1239. pEntityChunks,
  1240. UlCaptureNothing,
  1241. LocalSendInfo.Flags,
  1242. CaptureCache,
  1243. LocalSendInfo.pLogData,
  1244. &StatusCode,
  1245. &pResponse
  1246. );
  1247. if (!NT_SUCCESS(Status))
  1248. {
  1249. goto end;
  1250. }
  1251. }
  1252. //
  1253. // Apply ConnectionSendLimit and GlobalSendLimit. Only FromMemory
  1254. // chunks are taken into account plus the overhead. Do this before
  1255. // checking response flags because the check alters request's state.
  1256. //
  1257. if (FastSend)
  1258. {
  1259. SendBytes = BufferLength + g_UlFullTrackerSize;
  1260. }
  1261. else
  1262. {
  1263. ASSERT(UL_IS_VALID_INTERNAL_RESPONSE(pResponse));
  1264. SendBytes = pResponse->FromMemoryLength +
  1265. g_UlResponseBufferSize +
  1266. g_UlChunkTrackerSize;
  1267. }
  1268. Status = UlCheckSendLimit(
  1269. pRequest->pHttpConn,
  1270. SendBytes,
  1271. &ConnectionSendBytes,
  1272. &GlobalSendBytes
  1273. );
  1274. if (!NT_SUCCESS(Status))
  1275. {
  1276. goto end;
  1277. }
  1278. //
  1279. // Check pRequest->SentResponse and pRequest->SentLast flags.
  1280. //
  1281. Status = UlCheckSendHttpResponseFlags(
  1282. pRequest,
  1283. LocalSendInfo.Flags
  1284. );
  1285. if (!NT_SUCCESS(Status))
  1286. {
  1287. goto end;
  1288. }
  1289. //
  1290. // If this is for a zombie connection and not the last sendresponse
  1291. // then we will reject. Otherwise if the logging data is provided
  1292. // we will only do the logging and bail out.
  1293. //
  1294. Status = UlCheckForZombieConnection(
  1295. pRequest,
  1296. pRequest->pHttpConn,
  1297. LocalSendInfo.Flags,
  1298. LocalSendInfo.pLogData,
  1299. pIrp->RequestorMode
  1300. );
  1301. if (!NT_SUCCESS(Status))
  1302. {
  1303. goto end;
  1304. }
  1305. //
  1306. // Capture the user log data if we have a response captured.
  1307. //
  1308. if (pResponse && LocalSendInfo.pLogData && pRequest->SentLast == 1)
  1309. {
  1310. Status = UlCaptureUserLogData(
  1311. LocalSendInfo.pLogData,
  1312. pRequest,
  1313. &pResponse->pLogData
  1314. );
  1315. if (!NT_SUCCESS(Status))
  1316. {
  1317. goto end;
  1318. }
  1319. }
  1320. }
  1321. __except( UL_EXCEPTION_FILTER() )
  1322. {
  1323. Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode());
  1324. goto end;
  1325. }
  1326. ASSERT(NT_SUCCESS(Status));
  1327. if (FastSend)
  1328. {
  1329. Status = UlFastSendHttpResponse(
  1330. LocalSendInfo.pHttpResponse,
  1331. LocalSendInfo.pLogData,
  1332. pEntityChunks,
  1333. 1,
  1334. BufferLength,
  1335. NULL,
  1336. LocalSendInfo.Flags,
  1337. pRequest,
  1338. pIrp,
  1339. pIrp->RequestorMode,
  1340. ConnectionSendBytes,
  1341. GlobalSendBytes,
  1342. NULL
  1343. );
  1344. goto end;
  1345. }
  1346. //
  1347. // At this point, we'll definitely be initiating the
  1348. // send. Go ahead and mark the IRP as pending, then
  1349. // guarantee that we'll only return pending from
  1350. // this point on.
  1351. //
  1352. IoMarkIrpPending( pIrp );
  1353. //
  1354. // Remember ConnectionSendBytes and GlobalSendBytes. These are needed
  1355. // to uncheck send limit when the IRP is completed.
  1356. //
  1357. ASSERT(UL_IS_VALID_INTERNAL_RESPONSE(pResponse));
  1358. pResponse->ConnectionSendBytes = ConnectionSendBytes;
  1359. pResponse->GlobalSendBytes = GlobalSendBytes;
  1360. //
  1361. // Set CopySend flag on the response.
  1362. //
  1363. pResponse->CopySend = CopySend;
  1364. //
  1365. // Save the captured response in the IRP so we can dereference it
  1366. // after the IRP completes. The ownership of pResponse is transferred
  1367. // to the IRP beyond this point so we zap pResponse to avoid
  1368. // double-derefrence in the cleanup.
  1369. //
  1370. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer = pResponse;
  1371. pResponseCopy = pResponse;
  1372. pResponse = NULL;
  1373. //
  1374. // Prepare the response (open files, etc).
  1375. //
  1376. Status = UlPrepareHttpResponse(
  1377. pRequest->Version,
  1378. pHttpResponse,
  1379. pResponseCopy,
  1380. UserMode
  1381. );
  1382. if (NT_SUCCESS(Status))
  1383. {
  1384. //
  1385. // Try capture to cache and send
  1386. //
  1387. if (CaptureCache)
  1388. {
  1389. Status = UlCacheAndSendResponse(
  1390. pRequest,
  1391. pResponseCopy,
  1392. pAppPoolProcess,
  1393. LocalSendInfo.CachePolicy,
  1394. &UlpRestartSendHttpResponse,
  1395. pIrp,
  1396. &ServedFromCache
  1397. );
  1398. if (NT_SUCCESS(Status) && !ServedFromCache)
  1399. {
  1400. //
  1401. // Send the non-cached response
  1402. //
  1403. Status = UlSendHttpResponse(
  1404. pRequest,
  1405. pResponseCopy,
  1406. &UlpRestartSendHttpResponse,
  1407. pIrp
  1408. );
  1409. }
  1410. }
  1411. else
  1412. {
  1413. //
  1414. // Non-cacheable request/response, send response directly.
  1415. //
  1416. Status = UlSendHttpResponse(
  1417. pRequest,
  1418. pResponseCopy,
  1419. &UlpRestartSendHttpResponse,
  1420. pIrp
  1421. );
  1422. }
  1423. }
  1424. if (Status != STATUS_PENDING)
  1425. {
  1426. ASSERT(Status != STATUS_SUCCESS);
  1427. //
  1428. // UlSendHttpResponse either completed in-line
  1429. // (extremely unlikely) or failed (much more
  1430. // likely). Fake a completion to the completion
  1431. // routine so that the IRP will get completed
  1432. // properly, then map the return code to
  1433. // STATUS_PENDING, since we've already marked
  1434. // the IRP as such.
  1435. //
  1436. UlpRestartSendHttpResponse(
  1437. pIrp,
  1438. Status,
  1439. 0
  1440. );
  1441. CloseConnection = TRUE;
  1442. Status = STATUS_PENDING;
  1443. }
  1444. end:
  1445. //
  1446. // Free the local chunk array if we have allocated one.
  1447. //
  1448. if (pLocalEntityChunks)
  1449. {
  1450. UL_FREE_POOL(pLocalEntityChunks, UL_DATA_CHUNK_POOL_TAG);
  1451. }
  1452. //
  1453. // Close the connection if we hit an error.
  1454. //
  1455. if (pRequest)
  1456. {
  1457. //
  1458. // STATUS_OBJECT_PATH_NOT_FOUND means no cache chunk is found for the
  1459. // response to send, in which case we should not close the connection
  1460. // but rather let the user retry.
  1461. //
  1462. if ((NT_ERROR(Status) && STATUS_OBJECT_PATH_NOT_FOUND != Status) ||
  1463. CloseConnection)
  1464. {
  1465. UlCloseConnection(
  1466. pRequest->pHttpConn->pConnection,
  1467. TRUE,
  1468. NULL,
  1469. NULL
  1470. );
  1471. }
  1472. //
  1473. // Uncheck either ConnectionSendBytes or GlobalSendBytes while we
  1474. // still have a reference on the HttpConnection.
  1475. //
  1476. if (Status != STATUS_PENDING)
  1477. {
  1478. UlUncheckSendLimit(
  1479. pRequest->pHttpConn,
  1480. ConnectionSendBytes,
  1481. GlobalSendBytes
  1482. );
  1483. }
  1484. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  1485. }
  1486. if (pResponse)
  1487. {
  1488. ASSERT(UL_IS_VALID_INTERNAL_RESPONSE(pResponse));
  1489. UL_DEREFERENCE_INTERNAL_RESPONSE(pResponse);
  1490. }
  1491. //
  1492. // If the last response was an error case, log an error event here
  1493. //
  1494. if (ETW_LOG_MIN() && LastResponse &&
  1495. (NT_ERROR(Status) && Status != STATUS_OBJECT_PATH_NOT_FOUND))
  1496. {
  1497. UlEtwTraceEvent(
  1498. &UlTransGuid,
  1499. ETW_TYPE_SEND_ERROR,
  1500. (PVOID) &RequestId,
  1501. sizeof(HTTP_REQUEST_ID),
  1502. (PVOID) &StatusCode,
  1503. sizeof(USHORT),
  1504. NULL,
  1505. 0
  1506. );
  1507. }
  1508. if (Status != STATUS_PENDING)
  1509. {
  1510. pIrp->IoStatus.Status = Status;
  1511. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  1512. }
  1513. RETURN(Status);
  1514. } // UlSendHttpResponseIoctl
  1515. /***************************************************************************++
  1516. Routine Description:
  1517. This routine sends an HTTP entity body.
  1518. Note: This is a METHOD_NEITHER IOCTL.
  1519. Arguments:
  1520. pIrp - Supplies a pointer to the IO request packet.
  1521. pIrpSp - Supplies a pointer to the IO stack location to use for this
  1522. request.
  1523. Return Value:
  1524. NTSTATUS - Completion status.
  1525. --***************************************************************************/
  1526. NTSTATUS
  1527. UlSendEntityBodyIoctl(
  1528. IN PIRP pIrp,
  1529. IN PIO_STACK_LOCATION pIrpSp
  1530. )
  1531. {
  1532. NTSTATUS Status;
  1533. PHTTP_SEND_HTTP_RESPONSE_INFO pSendInfo;
  1534. HTTP_SEND_HTTP_RESPONSE_INFO LocalSendInfo;
  1535. PUL_INTERNAL_RESPONSE pResponse = NULL;
  1536. PUL_INTERNAL_RESPONSE pResponseCopy;
  1537. PUL_INTERNAL_REQUEST pRequest = NULL;
  1538. PUL_APP_POOL_PROCESS pAppPoolProcess = NULL;
  1539. ULONG BufferLength = 0;
  1540. BOOLEAN FastSend = FALSE;
  1541. BOOLEAN CopySend = FALSE;
  1542. BOOLEAN CloseConnection = FALSE;
  1543. BOOLEAN LastResponse = FALSE;
  1544. HTTP_REQUEST_ID RequestId = HTTP_NULL_ID;
  1545. HTTP_DATA_CHUNK LocalEntityChunks[UL_LOCAL_CHUNKS];
  1546. PHTTP_DATA_CHUNK pLocalEntityChunks = NULL;
  1547. PHTTP_DATA_CHUNK pEntityChunks;
  1548. HTTP_LOG_FIELDS_DATA LocalLogData;
  1549. USHORT StatusCode = 0;
  1550. ULONGLONG SendBytes = 0;
  1551. ULONGLONG ConnectionSendBytes = 0;
  1552. ULONGLONG GlobalSendBytes = 0;
  1553. //
  1554. // Sanity check.
  1555. //
  1556. ASSERT_IOCTL_METHOD(NEITHER, SEND_ENTITY_BODY);
  1557. PAGED_CODE();
  1558. __try
  1559. {
  1560. VALIDATE_APP_POOL(pIrpSp, pAppPoolProcess, TRUE);
  1561. VALIDATE_SEND_INFO(
  1562. pIrp,
  1563. pIrpSp,
  1564. pSendInfo,
  1565. LocalSendInfo,
  1566. pEntityChunks,
  1567. pLocalEntityChunks,
  1568. LocalEntityChunks
  1569. );
  1570. VALIDATE_LOG_DATA(pIrp, LocalSendInfo, LocalLogData);
  1571. LastResponse = (BOOLEAN)
  1572. (0 == (LocalSendInfo.Flags & HTTP_SEND_RESPONSE_FLAG_MORE_DATA));
  1573. if (ETW_LOG_MIN() && LastResponse)
  1574. {
  1575. RequestId = LocalSendInfo.RequestId;
  1576. UlEtwTraceEvent(
  1577. &UlTransGuid,
  1578. ETW_TYPE_ULRECV_RESPBODY,
  1579. (PVOID) &RequestId,
  1580. sizeof(HTTP_REQUEST_ID),
  1581. NULL,
  1582. 0
  1583. );
  1584. }
  1585. UlTrace(SEND_RESPONSE, (
  1586. "http!UlSendEntityBodyIoctl - Flags = %X\n",
  1587. LocalSendInfo.Flags
  1588. ));
  1589. //
  1590. // Now get the request from the request id.
  1591. // This gives us a reference to the request.
  1592. //
  1593. pRequest = UlGetRequestFromId(LocalSendInfo.RequestId, pAppPoolProcess);
  1594. if (pRequest == NULL)
  1595. {
  1596. //
  1597. // Couldn't map the HTTP_REQUEST_ID.
  1598. //
  1599. Status = STATUS_CONNECTION_INVALID;
  1600. goto end;
  1601. }
  1602. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  1603. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pRequest->pHttpConn));
  1604. //
  1605. // Check if we need to perform a CopySend if this IRP is
  1606. // non-overlapped and this is not LastResponse.
  1607. //
  1608. if (g_UlEnableCopySend &&
  1609. !LastResponse &&
  1610. !pIrp->Overlay.AsynchronousParameters.UserApcRoutine &&
  1611. !pIrp->Overlay.AsynchronousParameters.UserApcContext)
  1612. {
  1613. CopySend = TRUE;
  1614. }
  1615. //
  1616. // Take the fast path if this is a single memory chunk that needs no
  1617. // retransmission (<= 64k).
  1618. //
  1619. if (!pRequest->SendInProgress && !CopySend
  1620. && LocalSendInfo.EntityChunkCount == 1
  1621. && pEntityChunks->DataChunkType == HttpDataChunkFromMemory
  1622. && pEntityChunks->FromMemory.BufferLength <= g_UlMaxBytesPerSend)
  1623. {
  1624. BufferLength = pEntityChunks->FromMemory.BufferLength;
  1625. FastSend = (BOOLEAN) (BufferLength > 0);
  1626. }
  1627. //
  1628. // OK, we have the connection. Now capture the incoming
  1629. // HTTP_RESPONSE structure and map it to our internal
  1630. // format if this is not a FastSend.
  1631. //
  1632. if (!FastSend)
  1633. {
  1634. Status = UlCaptureHttpResponse(
  1635. pAppPoolProcess,
  1636. NULL,
  1637. pRequest,
  1638. LocalSendInfo.EntityChunkCount,
  1639. pEntityChunks,
  1640. UlCaptureNothing,
  1641. LocalSendInfo.Flags,
  1642. FALSE,
  1643. LocalSendInfo.pLogData,
  1644. &StatusCode,
  1645. &pResponse
  1646. );
  1647. if (!NT_SUCCESS(Status))
  1648. {
  1649. goto end;
  1650. }
  1651. }
  1652. //
  1653. // Apply ConnectionSendLimit and GlobalSendLimit. Only FromMemory
  1654. // chunks are taken into account plus the overhead. Do this before
  1655. // checking response flags because the check alters request's state.
  1656. //
  1657. if (FastSend)
  1658. {
  1659. SendBytes = BufferLength + g_UlFullTrackerSize;
  1660. }
  1661. else
  1662. {
  1663. ASSERT(UL_IS_VALID_INTERNAL_RESPONSE(pResponse));
  1664. SendBytes = pResponse->FromMemoryLength +
  1665. g_UlResponseBufferSize +
  1666. g_UlChunkTrackerSize;
  1667. }
  1668. Status = UlCheckSendLimit(
  1669. pRequest->pHttpConn,
  1670. SendBytes,
  1671. &ConnectionSendBytes,
  1672. &GlobalSendBytes
  1673. );
  1674. if (!NT_SUCCESS(Status))
  1675. {
  1676. goto end;
  1677. }
  1678. //
  1679. // Check pRequest->SentResponse and pRequest->SentLast flags.
  1680. //
  1681. Status = UlCheckSendEntityBodyFlags(
  1682. pRequest,
  1683. LocalSendInfo.Flags
  1684. );
  1685. if (!NT_SUCCESS(Status))
  1686. {
  1687. goto end;
  1688. }
  1689. //
  1690. // If this is for a zombie connection and not the last sendresponse
  1691. // then we will reject. Otherwise if the logging data is provided
  1692. // we will only do the logging and bail out.
  1693. //
  1694. Status = UlCheckForZombieConnection(
  1695. pRequest,
  1696. pRequest->pHttpConn,
  1697. LocalSendInfo.Flags,
  1698. LocalSendInfo.pLogData,
  1699. pIrp->RequestorMode
  1700. );
  1701. if (!NT_SUCCESS(Status))
  1702. {
  1703. goto end;
  1704. }
  1705. //
  1706. // Capture the user log data if we have a response captured.
  1707. //
  1708. if (pResponse && LocalSendInfo.pLogData && pRequest->SentLast == 1)
  1709. {
  1710. Status = UlCaptureUserLogData(
  1711. LocalSendInfo.pLogData,
  1712. pRequest,
  1713. &pResponse->pLogData
  1714. );
  1715. if (!NT_SUCCESS(Status))
  1716. {
  1717. goto end;
  1718. }
  1719. }
  1720. }
  1721. __except( UL_EXCEPTION_FILTER() )
  1722. {
  1723. Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode());
  1724. goto end;
  1725. }
  1726. ASSERT(NT_SUCCESS(Status));
  1727. ASSERT(LocalSendInfo.pHttpResponse == NULL);
  1728. if (FastSend)
  1729. {
  1730. Status = UlFastSendHttpResponse(
  1731. NULL,
  1732. LocalSendInfo.pLogData,
  1733. pEntityChunks,
  1734. 1,
  1735. BufferLength,
  1736. NULL,
  1737. LocalSendInfo.Flags,
  1738. pRequest,
  1739. pIrp,
  1740. pIrp->RequestorMode,
  1741. ConnectionSendBytes,
  1742. GlobalSendBytes,
  1743. NULL
  1744. );
  1745. goto end;
  1746. }
  1747. //
  1748. // At this point, we'll definitely be initiating the
  1749. // send. Go ahead and mark the IRP as pending, then
  1750. // guarantee that we'll only return pending from
  1751. // this point on.
  1752. //
  1753. IoMarkIrpPending( pIrp );
  1754. // Remember ConnectionSendBytes and GlobalSendBytes. These are needed
  1755. // to uncheck send limit when the IRP is completed.
  1756. //
  1757. ASSERT(UL_IS_VALID_INTERNAL_RESPONSE(pResponse));
  1758. pResponse->ConnectionSendBytes = ConnectionSendBytes;
  1759. pResponse->GlobalSendBytes = GlobalSendBytes;
  1760. //
  1761. // Set CopySend flag on the response.
  1762. //
  1763. pResponse->CopySend = CopySend;
  1764. //
  1765. // Save the captured response in the IRP so we can dereference it
  1766. // after the IRP completes. The ownership of pResponse is transferred
  1767. // to the IRP beyond this point so we zap pResponse to avoid
  1768. // double-derefrence in the cleanup.
  1769. //
  1770. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer = pResponse;
  1771. pResponseCopy = pResponse;
  1772. pResponse = NULL;
  1773. //
  1774. // Prepare the response (open files, etc).
  1775. //
  1776. Status = UlPrepareHttpResponse(
  1777. pRequest->Version,
  1778. NULL,
  1779. pResponseCopy,
  1780. UserMode
  1781. );
  1782. if (NT_SUCCESS(Status))
  1783. {
  1784. //
  1785. // Send the response
  1786. //
  1787. Status = UlSendHttpResponse(
  1788. pRequest,
  1789. pResponseCopy,
  1790. &UlpRestartSendHttpResponse,
  1791. pIrp
  1792. );
  1793. }
  1794. if (Status != STATUS_PENDING)
  1795. {
  1796. ASSERT(Status != STATUS_SUCCESS);
  1797. //
  1798. // UlSendHttpResponse either completed in-line
  1799. // (extremely unlikely) or failed (much more
  1800. // likely). Fake a completion to the completion
  1801. // routine so that the IRP will get completed
  1802. // properly, then map the return code to
  1803. // STATUS_PENDING, since we've already marked
  1804. // the IRP as such.
  1805. //
  1806. UlpRestartSendHttpResponse(
  1807. pIrp,
  1808. Status,
  1809. 0
  1810. );
  1811. CloseConnection = TRUE;
  1812. Status = STATUS_PENDING;
  1813. }
  1814. end:
  1815. //
  1816. // Free the local chunk array if we have allocated one.
  1817. //
  1818. if (pLocalEntityChunks)
  1819. {
  1820. UL_FREE_POOL(pLocalEntityChunks, UL_DATA_CHUNK_POOL_TAG);
  1821. }
  1822. //
  1823. // Close the connection if we hit an error.
  1824. //
  1825. if (pRequest)
  1826. {
  1827. //
  1828. // STATUS_OBJECT_PATH_NOT_FOUND means no cache chunk is found for the
  1829. // response to send, in which case we should not close the connection
  1830. // but rather let the user retry.
  1831. //
  1832. if ((NT_ERROR(Status) && STATUS_OBJECT_PATH_NOT_FOUND != Status) ||
  1833. CloseConnection)
  1834. {
  1835. UlCloseConnection(
  1836. pRequest->pHttpConn->pConnection,
  1837. TRUE,
  1838. NULL,
  1839. NULL
  1840. );
  1841. }
  1842. //
  1843. // Uncheck either ConnectionSendBytes or GlobalSendBytes while we
  1844. // still have a reference on the HttpConnection.
  1845. //
  1846. if (Status != STATUS_PENDING)
  1847. {
  1848. UlUncheckSendLimit(
  1849. pRequest->pHttpConn,
  1850. ConnectionSendBytes,
  1851. GlobalSendBytes
  1852. );
  1853. }
  1854. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  1855. }
  1856. if (pResponse)
  1857. {
  1858. ASSERT(UL_IS_VALID_INTERNAL_RESPONSE(pResponse));
  1859. UL_DEREFERENCE_INTERNAL_RESPONSE(pResponse);
  1860. }
  1861. //
  1862. // If the last response was an error case, log an error event here
  1863. //
  1864. if (ETW_LOG_MIN() && LastResponse &&
  1865. (NT_ERROR(Status) && Status != STATUS_OBJECT_PATH_NOT_FOUND))
  1866. {
  1867. UlEtwTraceEvent(
  1868. &UlTransGuid,
  1869. ETW_TYPE_SEND_ERROR,
  1870. (PVOID) &RequestId,
  1871. sizeof(HTTP_REQUEST_ID),
  1872. (PVOID) &StatusCode,
  1873. sizeof(USHORT),
  1874. NULL,
  1875. 0
  1876. );
  1877. }
  1878. if (Status != STATUS_PENDING)
  1879. {
  1880. pIrp->IoStatus.Status = Status;
  1881. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  1882. }
  1883. RETURN(Status);
  1884. } // UlSendEntityBodyIoctl
  1885. /***************************************************************************++
  1886. Routine Description:
  1887. This routine flushes a URL or URL tree from the response cache.
  1888. Note: This is a METHOD_BUFFERED IOCTL.
  1889. Arguments:
  1890. pIrp - Supplies a pointer to the IO request packet.
  1891. pIrpSp - Supplies a pointer to the IO stack location to use for this
  1892. request.
  1893. Return Value:
  1894. NTSTATUS - Completion status.
  1895. --***************************************************************************/
  1896. NTSTATUS
  1897. UlFlushResponseCacheIoctl(
  1898. IN PIRP pIrp,
  1899. IN PIO_STACK_LOCATION pIrpSp
  1900. )
  1901. {
  1902. NTSTATUS Status = STATUS_SUCCESS;
  1903. PHTTP_FLUSH_RESPONSE_CACHE_INFO pInfo = NULL;
  1904. PUL_APP_POOL_PROCESS pProcess;
  1905. UNICODE_STRING FullyQualifiedUrl;
  1906. //
  1907. // sanity check.
  1908. //
  1909. ASSERT_IOCTL_METHOD(BUFFERED, FLUSH_RESPONSE_CACHE);
  1910. PAGED_CODE();
  1911. RtlInitEmptyUnicodeString(&FullyQualifiedUrl, NULL, 0);
  1912. VALIDATE_APP_POOL(pIrpSp, pProcess, TRUE);
  1913. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp,
  1914. HTTP_FLUSH_RESPONSE_CACHE_INFO, pInfo);
  1915. //
  1916. // Check the flag.
  1917. //
  1918. if (pInfo->Flags != (pInfo->Flags & HTTP_FLUSH_RESPONSE_FLAG_VALID))
  1919. {
  1920. Status = STATUS_INVALID_PARAMETER;
  1921. goto end;
  1922. }
  1923. Status =
  1924. UlProbeAndCaptureUnicodeString(
  1925. &pInfo->FullyQualifiedUrl,
  1926. pIrp->RequestorMode,
  1927. &FullyQualifiedUrl,
  1928. UNICODE_STRING_MAX_WCHAR_LEN
  1929. );
  1930. if (NT_SUCCESS(Status))
  1931. {
  1932. UlFlushCacheByUri(
  1933. FullyQualifiedUrl.Buffer,
  1934. FullyQualifiedUrl.Length,
  1935. pInfo->Flags,
  1936. pProcess
  1937. );
  1938. }
  1939. end:
  1940. UlFreeCapturedUnicodeString(&FullyQualifiedUrl);
  1941. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  1942. } // UlFlushResponseCacheIoctl
  1943. /***************************************************************************++
  1944. Routine Description:
  1945. This routine waits for demand start notifications.
  1946. Note: This is a METHOD_BUFFERED IOCTL.
  1947. Arguments:
  1948. pIrp - Supplies a pointer to the IO request packet.
  1949. pIrpSp - Supplies a pointer to the IO stack location to use for this
  1950. request.
  1951. Return Value:
  1952. NTSTATUS - Completion status.
  1953. --***************************************************************************/
  1954. NTSTATUS
  1955. UlWaitForDemandStartIoctl(
  1956. IN PIRP pIrp,
  1957. IN PIO_STACK_LOCATION pIrpSp
  1958. )
  1959. {
  1960. NTSTATUS Status = STATUS_SUCCESS;
  1961. PUL_APP_POOL_PROCESS pProcess;
  1962. //
  1963. // sanity check.
  1964. //
  1965. ASSERT_IOCTL_METHOD(BUFFERED, WAIT_FOR_DEMAND_START);
  1966. PAGED_CODE();
  1967. VALIDATE_APP_POOL(pIrpSp, pProcess, FALSE);
  1968. //
  1969. // make the call
  1970. //
  1971. UlTrace(IOCTL,
  1972. ("UlWaitForDemandStartIoctl: pAppPoolProcess=%p, pIrp=%p\n",
  1973. pProcess,
  1974. pIrp
  1975. ));
  1976. Status = UlWaitForDemandStart(pProcess, pIrp);
  1977. end:
  1978. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  1979. } // UlWaitForDemandStartIoctl
  1980. /***************************************************************************++
  1981. Routine Description:
  1982. This routine waits for the client to initiate a disconnect.
  1983. Note: This is a METHOD_BUFFERED IOCTL.
  1984. Arguments:
  1985. pIrp - Supplies a pointer to the IO request packet.
  1986. pIrpSp - Supplies a pointer to the IO stack location to use for this
  1987. request.
  1988. Return Value:
  1989. NTSTATUS - Completion status.
  1990. --***************************************************************************/
  1991. NTSTATUS
  1992. UlWaitForDisconnectIoctl(
  1993. IN PIRP pIrp,
  1994. IN PIO_STACK_LOCATION pIrpSp
  1995. )
  1996. {
  1997. NTSTATUS Status;
  1998. PHTTP_WAIT_FOR_DISCONNECT_INFO pInfo;
  1999. PUL_HTTP_CONNECTION pHttpConn = NULL;
  2000. PUL_APP_POOL_PROCESS pProcess;
  2001. //
  2002. // Sanity check.
  2003. //
  2004. ASSERT_IOCTL_METHOD(BUFFERED, WAIT_FOR_DISCONNECT);
  2005. PAGED_CODE();
  2006. VALIDATE_APP_POOL(pIrpSp, pProcess, TRUE);
  2007. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp,
  2008. HTTP_WAIT_FOR_DISCONNECT_INFO, pInfo);
  2009. //
  2010. // Chase down the connection.
  2011. //
  2012. pHttpConn = UlGetConnectionFromId( pInfo->ConnectionId );
  2013. if (!pHttpConn)
  2014. {
  2015. Status = STATUS_CONNECTION_INVALID;
  2016. goto end;
  2017. }
  2018. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pHttpConn));
  2019. //
  2020. // Do it.
  2021. //
  2022. Status = UlWaitForDisconnect(pProcess, pHttpConn, pIrp);
  2023. end:
  2024. if (pHttpConn)
  2025. {
  2026. UL_DEREFERENCE_HTTP_CONNECTION(pHttpConn);
  2027. }
  2028. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  2029. } // UlWaitForDisconnectIoctl
  2030. //
  2031. // Private functions.
  2032. //
  2033. /***************************************************************************++
  2034. Routine Description:
  2035. Completion routine for UlSendHttpResponse().
  2036. Arguments:
  2037. pCompletionContext - Supplies an uninterpreted context value
  2038. as passed to the asynchronous API. In this case, it's
  2039. actually a pointer to the user's IRP.
  2040. Status - Supplies the final completion status of the
  2041. asynchronous API.
  2042. Information - Optionally supplies additional information about
  2043. the completed operation, such as the number of bytes
  2044. transferred.
  2045. --***************************************************************************/
  2046. VOID
  2047. UlpRestartSendHttpResponse(
  2048. IN PVOID pCompletionContext,
  2049. IN NTSTATUS Status,
  2050. IN ULONG_PTR Information
  2051. )
  2052. {
  2053. PIRP pIrp;
  2054. PIO_STACK_LOCATION pIrpSp;
  2055. PUL_INTERNAL_RESPONSE pResponse;
  2056. //
  2057. // Snag the IRP from the completion context, fill in the completion
  2058. // status, then complete the IRP.
  2059. //
  2060. pIrp = (PIRP)pCompletionContext;
  2061. pIrpSp = IoGetCurrentIrpStackLocation( pIrp );
  2062. pResponse = (PUL_INTERNAL_RESPONSE)(
  2063. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer
  2064. );
  2065. ASSERT( UL_IS_VALID_INTERNAL_RESPONSE( pResponse ) );
  2066. //
  2067. // Set pResponse->pIrp and pResponse->IoStatus so we can complete the
  2068. // IRP when the reference of the response drops to 0.
  2069. //
  2070. pResponse->pIrp = pIrp;
  2071. pResponse->IoStatus.Status = Status;
  2072. pResponse->IoStatus.Information = Information;
  2073. //
  2074. // Drop the initial/last reference of the response.
  2075. //
  2076. UL_DEREFERENCE_INTERNAL_RESPONSE( pResponse );
  2077. } // UlpRestartSendHttpResponse
  2078. /***************************************************************************++
  2079. Routine Description:
  2080. This routine stops request processing on the filter channel and cancels
  2081. outstanding I/O.
  2082. Note: This is a METHOD_BUFFERED IOCTL.
  2083. Arguments:
  2084. pIrp - Supplies a pointer to the IO request packet.
  2085. pIrpSp - Supplies a pointer to the IO stack location to use for this
  2086. request.
  2087. Return Value:
  2088. NTSTATUS - Completion status.
  2089. --***************************************************************************/
  2090. NTSTATUS
  2091. UlShutdownFilterIoctl(
  2092. IN PIRP pIrp,
  2093. IN PIO_STACK_LOCATION pIrpSp
  2094. )
  2095. {
  2096. NTSTATUS Status = STATUS_SUCCESS;
  2097. PUL_FILTER_PROCESS pProcess;
  2098. //
  2099. // sanity check.
  2100. //
  2101. ASSERT_IOCTL_METHOD(BUFFERED, SHUTDOWN_FILTER_CHANNEL);
  2102. PAGED_CODE();
  2103. VALIDATE_FILTER_PROCESS(pIrpSp, pProcess);
  2104. //
  2105. // make the call
  2106. //
  2107. UlTrace(IOCTL,
  2108. ("UlShutdownFilterIoctl: pFilterProcess=%p, pIrp=%p\n",
  2109. pProcess,
  2110. pIrp
  2111. ));
  2112. UlShutdownFilterProcess(
  2113. pProcess
  2114. );
  2115. Status = STATUS_SUCCESS;
  2116. end:
  2117. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  2118. }
  2119. /***************************************************************************++
  2120. Routine Description:
  2121. This routine accepts a raw connection.
  2122. Note: This is a METHOD_OUT_DIRECT IOCTL.
  2123. Arguments:
  2124. pIrp - Supplies a pointer to the IO request packet.
  2125. pIrpSp - Supplies a pointer to the IO stack location to use for this
  2126. request.
  2127. Return Value:
  2128. NTSTATUS - Completion status.
  2129. --***************************************************************************/
  2130. NTSTATUS
  2131. UlFilterAcceptIoctl(
  2132. IN PIRP pIrp,
  2133. IN PIO_STACK_LOCATION pIrpSp
  2134. )
  2135. {
  2136. NTSTATUS Status;
  2137. PUL_FILTER_PROCESS pFilterProcess;
  2138. //
  2139. // Sanity check.
  2140. //
  2141. ASSERT_IOCTL_METHOD(OUT_DIRECT, FILTER_ACCEPT);
  2142. PAGED_CODE();
  2143. VALIDATE_FILTER_PROCESS(pIrpSp, pFilterProcess);
  2144. VALIDATE_OUTPUT_BUFFER_SIZE(pIrpSp, HTTP_RAW_CONNECTION_INFO);
  2145. VALIDATE_OUTPUT_BUFFER_ADDRESS_FROM_MDL(pIrp, HTTP_RAW_CONNECTION_INFO);
  2146. //
  2147. // make the call
  2148. //
  2149. Status = UlFilterAccept(pFilterProcess, pIrp);
  2150. end:
  2151. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  2152. } // UlFilterAcceptIoctl
  2153. /***************************************************************************++
  2154. Routine Description:
  2155. This routine closes a raw connection.
  2156. Note: This is a METHOD_BUFFERED IOCTL.
  2157. Arguments:
  2158. pIrp - Supplies a pointer to the IO request packet.
  2159. pIrpSp - Supplies a pointer to the IO stack location to use for this
  2160. request.
  2161. Return Value:
  2162. NTSTATUS - Completion status.
  2163. --***************************************************************************/
  2164. NTSTATUS
  2165. UlFilterCloseIoctl(
  2166. IN PIRP pIrp,
  2167. IN PIO_STACK_LOCATION pIrpSp
  2168. )
  2169. {
  2170. NTSTATUS Status;
  2171. PHTTP_RAW_CONNECTION_ID pConnectionId;
  2172. PUX_FILTER_CONNECTION pConnection = NULL;
  2173. PUL_FILTER_PROCESS pFilterProcess;
  2174. //
  2175. // Sanity check.
  2176. //
  2177. ASSERT_IOCTL_METHOD(BUFFERED, FILTER_CLOSE);
  2178. PAGED_CODE();
  2179. VALIDATE_FILTER_PROCESS(pIrpSp, pFilterProcess);
  2180. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp, HTTP_RAW_CONNECTION_ID,
  2181. pConnectionId);
  2182. pConnection = UlGetRawConnectionFromId(*pConnectionId);
  2183. if (!pConnection)
  2184. {
  2185. Status = STATUS_INVALID_PARAMETER;
  2186. goto end;
  2187. }
  2188. ASSERT(IS_VALID_FILTER_CONNECTION(pConnection));
  2189. //
  2190. // make the call
  2191. //
  2192. Status = UlFilterClose(pFilterProcess, pConnection, pIrp);
  2193. end:
  2194. if (pConnection)
  2195. {
  2196. DEREFERENCE_FILTER_CONNECTION(pConnection);
  2197. }
  2198. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  2199. } // UlFilterCloseIoctl
  2200. /***************************************************************************++
  2201. Routine Description:
  2202. This routine reads data from a raw connection.
  2203. Note: This is a METHOD_OUT_DIRECT IOCTL.
  2204. Arguments:
  2205. pIrp - Supplies a pointer to the IO request packet.
  2206. pIrpSp - Supplies a pointer to the IO stack location to use for this
  2207. request.
  2208. Return Value:
  2209. NTSTATUS - Completion status.
  2210. --***************************************************************************/
  2211. NTSTATUS
  2212. UlFilterRawReadIoctl(
  2213. IN PIRP pIrp,
  2214. IN PIO_STACK_LOCATION pIrpSp
  2215. )
  2216. {
  2217. NTSTATUS Status;
  2218. PHTTP_RAW_CONNECTION_ID pConnectionId;
  2219. PUX_FILTER_CONNECTION pConnection = NULL;
  2220. PUL_FILTER_PROCESS pFilterProcess;
  2221. //
  2222. // Sanity check.
  2223. //
  2224. ASSERT_IOCTL_METHOD(OUT_DIRECT, FILTER_RAW_READ);
  2225. PAGED_CODE();
  2226. VALIDATE_FILTER_PROCESS(pIrpSp, pFilterProcess);
  2227. VALIDATE_OUTPUT_BUFFER_SIZE(pIrpSp, UCHAR);
  2228. VALIDATE_OUTPUT_BUFFER_ADDRESS_FROM_MDL(pIrp, UCHAR);
  2229. //
  2230. // Immediately fork to the appropriate code if we're doing a combined
  2231. // read and write.
  2232. //
  2233. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength ==
  2234. sizeof(HTTP_FILTER_BUFFER_PLUS))
  2235. {
  2236. return UlFilterAppWriteAndRawRead(pIrp, pIrpSp);
  2237. }
  2238. __try
  2239. {
  2240. //
  2241. // Get the connection ID.
  2242. //
  2243. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp, HTTP_RAW_CONNECTION_ID,
  2244. pConnectionId);
  2245. pConnection = UlGetRawConnectionFromId(*pConnectionId);
  2246. if (!pConnection)
  2247. {
  2248. Status = STATUS_INVALID_PARAMETER;
  2249. goto end;
  2250. }
  2251. ASSERT(IS_VALID_FILTER_CONNECTION(pConnection));
  2252. Status = UlFilterRawRead(pFilterProcess, pConnection, pIrp);
  2253. }
  2254. __except( UL_EXCEPTION_FILTER() )
  2255. {
  2256. Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode());
  2257. UlTrace( FILTER, (
  2258. "UlFilterRawReadIoctl: Exception hit! 0x%08X\n",
  2259. Status
  2260. ));
  2261. }
  2262. end:
  2263. if (pConnection)
  2264. {
  2265. DEREFERENCE_FILTER_CONNECTION(pConnection);
  2266. }
  2267. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  2268. } // UlFilterRawReadIoctl
  2269. /***************************************************************************++
  2270. Routine Description:
  2271. This routine writes data to a raw connection.
  2272. Note: This is a METHOD_IN_DIRECT IOCTL.
  2273. Arguments:
  2274. pIrp - Supplies a pointer to the IO request packet.
  2275. pIrpSp - Supplies a pointer to the IO stack location to use for this
  2276. request.
  2277. Return Value:
  2278. NTSTATUS - Completion status.
  2279. --***************************************************************************/
  2280. NTSTATUS
  2281. UlFilterRawWriteIoctl(
  2282. IN PIRP pIrp,
  2283. IN PIO_STACK_LOCATION pIrpSp
  2284. )
  2285. {
  2286. NTSTATUS Status;
  2287. PHTTP_RAW_CONNECTION_ID pConnectionId;
  2288. PUX_FILTER_CONNECTION pConnection = NULL;
  2289. PUL_FILTER_PROCESS pFilterProcess;
  2290. BOOLEAN MarkedPending = FALSE;
  2291. //
  2292. // Sanity check.
  2293. //
  2294. ASSERT_IOCTL_METHOD(IN_DIRECT, FILTER_RAW_WRITE);
  2295. PAGED_CODE();
  2296. __try
  2297. {
  2298. VALIDATE_FILTER_PROCESS(pIrpSp, pFilterProcess);
  2299. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp, HTTP_RAW_CONNECTION_ID,
  2300. pConnectionId);
  2301. if (!pIrp->MdlAddress)
  2302. {
  2303. Status = STATUS_INVALID_PARAMETER;
  2304. goto end;
  2305. }
  2306. pConnection = UlGetRawConnectionFromId(*pConnectionId);
  2307. if (!pConnection)
  2308. {
  2309. Status = STATUS_INVALID_PARAMETER;
  2310. goto end;
  2311. }
  2312. ASSERT(IS_VALID_FILTER_CONNECTION(pConnection));
  2313. //
  2314. // make the call
  2315. //
  2316. IoMarkIrpPending(pIrp);
  2317. MarkedPending = TRUE;
  2318. Status = UlFilterRawWrite(
  2319. pFilterProcess,
  2320. pConnection,
  2321. pIrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  2322. pIrp
  2323. );
  2324. }
  2325. __except( UL_EXCEPTION_FILTER() )
  2326. {
  2327. Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode());
  2328. UlTrace( FILTER, (
  2329. "UlFilterRawWriteIoctl: Exception hit! 0x%08X\n",
  2330. Status
  2331. ));
  2332. }
  2333. end:
  2334. if (pConnection)
  2335. {
  2336. DEREFERENCE_FILTER_CONNECTION(pConnection);
  2337. }
  2338. //
  2339. // complete the request?
  2340. //
  2341. if (Status != STATUS_PENDING)
  2342. {
  2343. pIrp->IoStatus.Status = Status;
  2344. UlCompleteRequest( pIrp, IO_NO_INCREMENT );
  2345. if (MarkedPending)
  2346. {
  2347. //
  2348. // Since we marked the IRP pending, we should return pending.
  2349. //
  2350. Status = STATUS_PENDING;
  2351. }
  2352. }
  2353. else
  2354. {
  2355. //
  2356. // If we're returning pending, the IRP better be marked pending.
  2357. //
  2358. ASSERT(MarkedPending);
  2359. }
  2360. RETURN( Status );
  2361. } // UlFilterRawWriteIoctl
  2362. /***************************************************************************++
  2363. Routine Description:
  2364. This routine reads data from an http application.
  2365. Note: This is a METHOD_OUT_DIRECT IOCTL.
  2366. Arguments:
  2367. pIrp - Supplies a pointer to the IO request packet.
  2368. pIrpSp - Supplies a pointer to the IO stack location to use for this
  2369. request.
  2370. Return Value:
  2371. NTSTATUS - Completion status.
  2372. --***************************************************************************/
  2373. NTSTATUS
  2374. UlFilterAppReadIoctl(
  2375. IN PIRP pIrp,
  2376. IN PIO_STACK_LOCATION pIrpSp
  2377. )
  2378. {
  2379. NTSTATUS Status;
  2380. PUX_FILTER_CONNECTION pConnection = NULL;
  2381. PHTTP_FILTER_BUFFER pFiltBuffer;
  2382. PUL_FILTER_PROCESS pFilterProcess;
  2383. //
  2384. // Sanity check.
  2385. //
  2386. ASSERT_IOCTL_METHOD(OUT_DIRECT, FILTER_APP_READ);
  2387. PAGED_CODE();
  2388. //
  2389. // Immediately fork to the appropriate code if we're doing a combined
  2390. // read and write.
  2391. //
  2392. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength ==
  2393. sizeof(HTTP_FILTER_BUFFER_PLUS))
  2394. {
  2395. return UlFilterRawWriteAndAppRead(pIrp, pIrpSp);
  2396. }
  2397. __try
  2398. {
  2399. VALIDATE_FILTER_PROCESS(pIrpSp, pFilterProcess);
  2400. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp, HTTP_FILTER_BUFFER, pFiltBuffer);
  2401. VALIDATE_OUTPUT_BUFFER_SIZE(pIrpSp, HTTP_FILTER_BUFFER);
  2402. VALIDATE_OUTPUT_BUFFER_ADDRESS_FROM_MDL(pIrp, HTTP_FILTER_BUFFER);
  2403. //
  2404. // Map the incoming connection ID to the corresponding
  2405. // UX_FILTER_CONNECTION object.
  2406. //
  2407. pConnection = UlGetRawConnectionFromId(pFiltBuffer->Reserved);
  2408. if (!pConnection)
  2409. {
  2410. Status = STATUS_INVALID_PARAMETER;
  2411. goto end;
  2412. }
  2413. ASSERT(IS_VALID_FILTER_CONNECTION(pConnection));
  2414. Status = UlFilterAppRead(pFilterProcess, pConnection, pIrp);
  2415. }
  2416. __except( UL_EXCEPTION_FILTER() )
  2417. {
  2418. Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode());
  2419. UlTrace( FILTER, (
  2420. "UlFilterAppReadIoctl: Exception hit! 0x%08X\n",
  2421. Status
  2422. ));
  2423. }
  2424. end:
  2425. if (pConnection)
  2426. {
  2427. DEREFERENCE_FILTER_CONNECTION(pConnection);
  2428. }
  2429. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  2430. } // UlFilterAppReadIoctl
  2431. /***************************************************************************++
  2432. Routine Description:
  2433. This routine writes data to an http application.
  2434. Note: This is a METHOD_IN_DIRECT IOCTL.
  2435. Arguments:
  2436. pIrp - Supplies a pointer to the IO request packet.
  2437. pIrpSp - Supplies a pointer to the IO stack location to use for this
  2438. request.
  2439. Return Value:
  2440. NTSTATUS - Completion status.
  2441. --***************************************************************************/
  2442. NTSTATUS
  2443. UlFilterAppWriteIoctl(
  2444. IN PIRP pIrp,
  2445. IN PIO_STACK_LOCATION pIrpSp
  2446. )
  2447. {
  2448. NTSTATUS Status;
  2449. PUX_FILTER_CONNECTION pConnection = NULL;
  2450. BOOLEAN MarkedPending = FALSE;
  2451. PHTTP_FILTER_BUFFER pFiltBuffer;
  2452. PUL_FILTER_PROCESS pFilterProcess;
  2453. //
  2454. // Sanity check.
  2455. //
  2456. ASSERT_IOCTL_METHOD(IN_DIRECT, FILTER_APP_WRITE);
  2457. PAGED_CODE();
  2458. __try
  2459. {
  2460. VALIDATE_FILTER_PROCESS(pIrpSp, pFilterProcess);
  2461. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp, HTTP_FILTER_BUFFER, pFiltBuffer);
  2462. //
  2463. // Map the incoming connection ID to the corresponding
  2464. // UX_FILTER_CONNECTION object.
  2465. //
  2466. pConnection = UlGetRawConnectionFromId(pFiltBuffer->Reserved);
  2467. if (!pConnection)
  2468. {
  2469. Status = STATUS_INVALID_PARAMETER;
  2470. goto end;
  2471. }
  2472. ASSERT(IS_VALID_FILTER_CONNECTION(pConnection));
  2473. //
  2474. // make the call
  2475. //
  2476. IoMarkIrpPending(pIrp);
  2477. MarkedPending = TRUE;
  2478. Status = UlFilterAppWrite(pFilterProcess, pConnection, pIrp);
  2479. }
  2480. __except( UL_EXCEPTION_FILTER() )
  2481. {
  2482. Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode());
  2483. UlTrace( FILTER, (
  2484. "UlFilterAppWriteIoctl: Exception hit! 0x%08X\n",
  2485. Status
  2486. ));
  2487. }
  2488. end:
  2489. if (pConnection)
  2490. {
  2491. DEREFERENCE_FILTER_CONNECTION(pConnection);
  2492. }
  2493. //
  2494. // complete the request?
  2495. //
  2496. if (Status != STATUS_PENDING)
  2497. {
  2498. pIrp->IoStatus.Status = Status;
  2499. UlCompleteRequest( pIrp, IO_NO_INCREMENT );
  2500. if (MarkedPending)
  2501. {
  2502. //
  2503. // Since we marked the IRP pending, we should return pending.
  2504. //
  2505. Status = STATUS_PENDING;
  2506. }
  2507. }
  2508. else
  2509. {
  2510. //
  2511. // If we're returning pending, the IRP better be marked pending.
  2512. //
  2513. ASSERT(MarkedPending);
  2514. }
  2515. RETURN( Status );
  2516. } // UlFilterAppWriteIoctl
  2517. /***************************************************************************++
  2518. Routine Description:
  2519. This routine asks the SSL helper for a client certificate.
  2520. Note: This is a METHOD_OUT_DIRECT IOCTL.
  2521. Arguments:
  2522. pIrp - Supplies a pointer to the IO request packet.
  2523. pIrpSp - Supplies a pointer to the IO stack location to use for this
  2524. request.
  2525. Return Value:
  2526. NTSTATUS - Completion status.
  2527. --***************************************************************************/
  2528. NTSTATUS
  2529. UlReceiveClientCertIoctl(
  2530. IN PIRP pIrp,
  2531. IN PIO_STACK_LOCATION pIrpSp
  2532. )
  2533. {
  2534. NTSTATUS Status;
  2535. PHTTP_FILTER_RECEIVE_CLIENT_CERT_INFO pReceiveCertInfo;
  2536. PUL_HTTP_CONNECTION pHttpConn = NULL;
  2537. PUL_APP_POOL_PROCESS pProcess;
  2538. //
  2539. // Sanity check.
  2540. //
  2541. ASSERT_IOCTL_METHOD(OUT_DIRECT, FILTER_RECEIVE_CLIENT_CERT);
  2542. PAGED_CODE();
  2543. __try
  2544. {
  2545. VALIDATE_APP_POOL(pIrpSp, pProcess, TRUE);
  2546. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp,
  2547. HTTP_FILTER_RECEIVE_CLIENT_CERT_INFO,
  2548. pReceiveCertInfo);
  2549. VALIDATE_OUTPUT_BUFFER_SIZE(pIrpSp, HTTP_SSL_CLIENT_CERT_INFO);
  2550. VALIDATE_OUTPUT_BUFFER_ADDRESS_FROM_MDL(pIrp, PVOID);
  2551. //
  2552. // Map the incoming connection ID to the corresponding
  2553. // HTTP_CONNECTION object.
  2554. //
  2555. pHttpConn = UlGetConnectionFromId(pReceiveCertInfo->ConnectionId);
  2556. if (!pHttpConn)
  2557. {
  2558. Status = STATUS_CONNECTION_INVALID;
  2559. goto end;
  2560. }
  2561. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pHttpConn));
  2562. //
  2563. // make the call
  2564. //
  2565. Status = UlReceiveClientCert(
  2566. pProcess,
  2567. &pHttpConn->pConnection->FilterInfo,
  2568. pReceiveCertInfo->Flags,
  2569. pIrp
  2570. );
  2571. }
  2572. __except( UL_EXCEPTION_FILTER() )
  2573. {
  2574. Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode());
  2575. }
  2576. end:
  2577. if (pHttpConn)
  2578. {
  2579. UL_DEREFERENCE_HTTP_CONNECTION(pHttpConn);
  2580. }
  2581. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  2582. } // UlFilterReceiveClientCertIoctl
  2583. /***************************************************************************++
  2584. Routine Description:
  2585. This routine returns the perfmon counter data for this driver
  2586. Note: This is a METHOD_OUT_DIRECT IOCTL.
  2587. Arguments:
  2588. pIrp - Supplies a pointer to the IO request packet.
  2589. pIrpSp - Supplies a pointer to the IO stack location to use for this
  2590. request.
  2591. Return Value:
  2592. NTSTATUS - Completion status.
  2593. --***************************************************************************/
  2594. NTSTATUS
  2595. UlGetCountersIoctl(
  2596. IN PIRP pIrp,
  2597. IN PIO_STACK_LOCATION pIrpSp
  2598. )
  2599. {
  2600. NTSTATUS Status = STATUS_SUCCESS;
  2601. PUL_CONTROL_CHANNEL pControlChannel;
  2602. PVOID pMdlBuffer = NULL;
  2603. PHTTP_COUNTER_GROUP pCounterGroup = NULL;
  2604. ULONG Blocks;
  2605. ULONG Length =
  2606. pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  2607. //
  2608. // Sanity check.
  2609. //
  2610. ASSERT_IOCTL_METHOD(OUT_DIRECT, GET_COUNTERS);
  2611. PAGED_CODE();
  2612. //
  2613. // If not returning STATUS_SUCCESS,
  2614. // IoStatus.Information *must* be 0.
  2615. //
  2616. pIrp->IoStatus.Information = 0;
  2617. //
  2618. // Validate Parameters
  2619. //
  2620. VALIDATE_CONTROL_CHANNEL(pIrpSp, pControlChannel);
  2621. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp, HTTP_COUNTER_GROUP, pCounterGroup);
  2622. // Crack IRP and get MDL containing user's buffer
  2623. // Crack MDL to get user's buffer
  2624. // if no outbut buffer pass down in the Irp
  2625. // that means app is asking for the required
  2626. // field length
  2627. if ( NULL != pIrp->MdlAddress )
  2628. {
  2629. GET_OUTPUT_BUFFER_ADDRESS_FROM_MDL(pIrp, pMdlBuffer);
  2630. }
  2631. //
  2632. // Call support function to gather appropriate counter blocks
  2633. // and place in user's buffer.
  2634. //
  2635. if (HttpCounterGroupGlobal == *pCounterGroup)
  2636. {
  2637. VALIDATE_BUFFER_ALIGNMENT(pMdlBuffer, HTTP_GLOBAL_COUNTERS);
  2638. Status = UlGetGlobalCounters(
  2639. pMdlBuffer,
  2640. Length,
  2641. &Length
  2642. );
  2643. }
  2644. else
  2645. if (HttpCounterGroupSite == *pCounterGroup)
  2646. {
  2647. VALIDATE_BUFFER_ALIGNMENT(pMdlBuffer, HTTP_SITE_COUNTERS);
  2648. Status = UlGetSiteCounters(
  2649. pControlChannel,
  2650. pMdlBuffer,
  2651. Length,
  2652. &Length,
  2653. &Blocks
  2654. );
  2655. }
  2656. else
  2657. {
  2658. Status = STATUS_NOT_IMPLEMENTED;
  2659. }
  2660. if ( NT_SUCCESS(Status) || NT_INFORMATION(Status) )
  2661. {
  2662. pIrp->IoStatus.Information = (ULONG_PTR)Length;
  2663. }
  2664. end:
  2665. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  2666. } // UlGetCountersIoctl
  2667. /***************************************************************************++
  2668. Routine Description:
  2669. This routine adds a fragment cache entry.
  2670. Note: This is a METHOD_BUFFERED IOCTL.
  2671. Arguments:
  2672. pIrp - Supplies a pointer to the IO request packet.
  2673. pIrpSp - Supplies a pointer to the IO stack location to use for this
  2674. request.
  2675. Return Value:
  2676. NTSTATUS - Completion status.
  2677. --***************************************************************************/
  2678. NTSTATUS
  2679. UlAddFragmentToCacheIoctl(
  2680. IN PIRP pIrp,
  2681. IN PIO_STACK_LOCATION pIrpSp
  2682. )
  2683. {
  2684. NTSTATUS Status;
  2685. PHTTP_ADD_FRAGMENT_INFO pInfo = NULL;
  2686. PUL_APP_POOL_PROCESS pProcess;
  2687. //
  2688. // Sanity check.
  2689. //
  2690. ASSERT_IOCTL_METHOD(BUFFERED, ADD_FRAGMENT_TO_CACHE);
  2691. PAGED_CODE();
  2692. VALIDATE_APP_POOL(pIrpSp, pProcess, TRUE);
  2693. VALIDATE_INPUT_BUFFER(pIrp, pIrpSp, HTTP_ADD_FRAGMENT_INFO, pInfo);
  2694. //
  2695. // Add a new fragment cache entry.
  2696. //
  2697. Status = UlAddFragmentToCache(
  2698. pProcess,
  2699. &pInfo->FragmentName,
  2700. &pInfo->DataChunk,
  2701. &pInfo->CachePolicy,
  2702. pIrp->RequestorMode
  2703. );
  2704. end:
  2705. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  2706. } // UlAddFragmentToCacheIoctl
  2707. /***************************************************************************++
  2708. Routine Description:
  2709. This routine reads the data back from the fragment cache entry.
  2710. Note: This is a METHOD_OUT_DIRECT IOCTL.
  2711. Arguments:
  2712. pIrp - Supplies a pointer to the IO request packet.
  2713. pIrpSp - Supplies a pointer to the IO stack location to use for this
  2714. request.
  2715. Return Value:
  2716. NTSTATUS - Completion status.
  2717. --***************************************************************************/
  2718. NTSTATUS
  2719. UlReadFragmentFromCacheIoctl(
  2720. IN PIRP pIrp,
  2721. IN PIO_STACK_LOCATION pIrpSp
  2722. )
  2723. {
  2724. NTSTATUS Status = STATUS_SUCCESS;
  2725. PUL_APP_POOL_PROCESS pProcess;
  2726. ULONG BytesRead = 0;
  2727. //
  2728. // Sanity check.
  2729. //
  2730. ASSERT_IOCTL_METHOD(NEITHER, READ_FRAGMENT_FROM_CACHE);
  2731. PAGED_CODE();
  2732. //
  2733. // Initialize total bytes read.
  2734. //
  2735. pIrp->IoStatus.Information = 0;
  2736. VALIDATE_APP_POOL(pIrpSp, pProcess, TRUE);
  2737. Status = UlReadFragmentFromCache(
  2738. pProcess,
  2739. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  2740. pIrpSp->Parameters.DeviceIoControl.InputBufferLength,
  2741. pIrp->UserBuffer,
  2742. pIrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  2743. pIrp->RequestorMode,
  2744. &BytesRead
  2745. );
  2746. pIrp->IoStatus.Information = BytesRead;
  2747. end:
  2748. COMPLETE_REQUEST_AND_RETURN( pIrp, Status );
  2749. } // UlReadFragmentFromCacheIoctl
  2750. /***************************************************************************++
  2751. Routine Description:
  2752. This routine sends Entity body on a request.
  2753. Arguments:
  2754. pIrp - Supplies a pointer to the IO request packet.
  2755. pIrpSp - Supplies a pointer to the IO stack location to use for this
  2756. request.
  2757. Return Value:
  2758. NTSTATUS - Completion status.
  2759. --***************************************************************************/
  2760. NTSTATUS
  2761. UcSendEntityBodyIoctl(
  2762. IN PIRP pIrp,
  2763. IN PIO_STACK_LOCATION pIrpSp
  2764. )
  2765. {
  2766. NTSTATUS Status;
  2767. PHTTP_SEND_REQUEST_ENTITY_BODY_INFO pSendInfo;
  2768. PUC_HTTP_REQUEST pRequest = 0;
  2769. PUC_HTTP_SEND_ENTITY_BODY pKeEntity = 0;
  2770. KIRQL OldIrql;
  2771. BOOLEAN bDontFail = FALSE;
  2772. BOOLEAN bLast;
  2773. //
  2774. // Sanity check.
  2775. //
  2776. ASSERT_IOCTL_METHOD(IN_DIRECT, SEND_REQUEST_ENTITY_BODY);
  2777. PAGED_CODE();
  2778. do
  2779. {
  2780. //
  2781. // Ensure this is really an app pool, not a control channel.
  2782. //
  2783. if (IS_SERVER(pIrpSp->FileObject) == FALSE)
  2784. {
  2785. //
  2786. // Not an server
  2787. //
  2788. Status = STATUS_INVALID_HANDLE;
  2789. UC_WRITE_TRACE_LOG(
  2790. g_pUcTraceLog,
  2791. UC_ACTION_ENTITY_NEW,
  2792. NULL,
  2793. NULL,
  2794. NULL,
  2795. UlongToPtr(Status)
  2796. );
  2797. break;
  2798. }
  2799. //
  2800. // Ensure the input buffer is large enough.
  2801. //
  2802. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength <
  2803. sizeof(*pSendInfo))
  2804. {
  2805. //
  2806. // Input buffer too small.
  2807. //
  2808. Status = STATUS_BUFFER_TOO_SMALL;
  2809. UC_WRITE_TRACE_LOG(
  2810. g_pUcTraceLog,
  2811. UC_ACTION_ENTITY_NEW,
  2812. NULL,
  2813. NULL,
  2814. NULL,
  2815. UlongToPtr(Status)
  2816. );
  2817. break;
  2818. }
  2819. pSendInfo =
  2820. (PHTTP_SEND_REQUEST_ENTITY_BODY_INFO)pIrp->AssociatedIrp.SystemBuffer;
  2821. //
  2822. // Now get the request from the request id.
  2823. // This gives us a reference to the request.
  2824. //
  2825. // NOTE: We don't have to worry about the RequestID being changed,
  2826. // since it's not a pointer.
  2827. //
  2828. pRequest = (PUC_HTTP_REQUEST)
  2829. UlGetObjectFromOpaqueId(pSendInfo->RequestID,
  2830. UlOpaqueIdTypeHttpRequest,
  2831. UcReferenceRequest);
  2832. if (UC_IS_VALID_HTTP_REQUEST(pRequest) == FALSE)
  2833. {
  2834. //
  2835. // Couldn't map the UL_HTTP_REQUEST_ID.
  2836. //
  2837. Status = STATUS_INVALID_PARAMETER;
  2838. UC_WRITE_TRACE_LOG(
  2839. g_pUcTraceLog,
  2840. UC_ACTION_ENTITY_NEW,
  2841. pRequest,
  2842. NULL,
  2843. NULL,
  2844. UlongToPtr(Status)
  2845. );
  2846. break;
  2847. }
  2848. if(pRequest->pFileObject != pIrpSp->FileObject)
  2849. {
  2850. //
  2851. // Cant allow the app to use someone else's RequestID
  2852. //
  2853. Status = STATUS_INVALID_PARAMETER;
  2854. UC_WRITE_TRACE_LOG(
  2855. g_pUcTraceLog,
  2856. UC_ACTION_ENTITY_NEW,
  2857. pRequest,
  2858. NULL,
  2859. NULL,
  2860. UlongToPtr(Status)
  2861. );
  2862. break;
  2863. }
  2864. if(pSendInfo->Flags & (~HTTP_SEND_REQUEST_FLAG_VALID))
  2865. {
  2866. Status = STATUS_INVALID_PARAMETER;
  2867. UC_WRITE_TRACE_LOG(
  2868. g_pUcTraceLog,
  2869. UC_ACTION_ENTITY_NEW,
  2870. pRequest,
  2871. NULL,
  2872. NULL,
  2873. UlongToPtr(Status)
  2874. );
  2875. break;
  2876. }
  2877. bLast = FALSE;
  2878. if(!(pSendInfo->Flags & HTTP_SEND_REQUEST_FLAG_MORE_DATA))
  2879. {
  2880. //
  2881. // Remember that this was the last send. We shouldn't
  2882. // get any more data after this.
  2883. //
  2884. bLast = TRUE;
  2885. }
  2886. ExAcquireFastMutex(&pRequest->Mutex);
  2887. Status = UcCaptureEntityBody(
  2888. pSendInfo,
  2889. pIrp,
  2890. pRequest,
  2891. &pKeEntity,
  2892. bLast
  2893. );
  2894. ExReleaseFastMutex(&pRequest->Mutex);
  2895. if(!NT_SUCCESS(Status))
  2896. {
  2897. //
  2898. // NOTE: If the SendEntity IRP fails for some reason or the other,
  2899. // we will be failing the entire request. This simplifies the code
  2900. // somewhat (For e.g. When we get a entity, we record some state
  2901. // in UC_HTTP_REQUEST. If we were not failing the entire request,
  2902. // we would have to unwind the state if an entity failed). It's a
  2903. // lot simpler to just fail the entire request and get the app to
  2904. // post another one.
  2905. //
  2906. UC_WRITE_TRACE_LOG(
  2907. g_pUcTraceLog,
  2908. UC_ACTION_ENTITY_NEW,
  2909. NULL,
  2910. NULL,
  2911. NULL,
  2912. UlongToPtr(Status)
  2913. );
  2914. break;
  2915. }
  2916. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer = pKeEntity;
  2917. UC_WRITE_TRACE_LOG(
  2918. g_pUcTraceLog,
  2919. UC_ACTION_ENTITY_NEW,
  2920. pRequest,
  2921. pKeEntity,
  2922. pIrp,
  2923. UlongToPtr(Status)
  2924. );
  2925. Status = UcSendEntityBody(pRequest,
  2926. pKeEntity,
  2927. pIrp,
  2928. pIrpSp,
  2929. &bDontFail,
  2930. bLast
  2931. );
  2932. } while(FALSE);
  2933. if(Status == STATUS_SUCCESS)
  2934. {
  2935. pIrp->IoStatus.Status = Status;
  2936. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  2937. }
  2938. else if(Status != STATUS_PENDING)
  2939. {
  2940. if(pKeEntity)
  2941. {
  2942. ASSERT(pRequest);
  2943. UcFreeSendMdls(pKeEntity->pMdlHead);
  2944. UL_FREE_POOL_WITH_QUOTA(
  2945. pKeEntity,
  2946. UC_ENTITY_POOL_TAG,
  2947. NonPagedPool,
  2948. pKeEntity->BytesAllocated,
  2949. pRequest->pServerInfo->pProcess
  2950. );
  2951. }
  2952. if(pRequest)
  2953. {
  2954. if(!bDontFail)
  2955. {
  2956. UlAcquireSpinLock(&pRequest->pConnection->SpinLock, &OldIrql);
  2957. UcFailRequest(pRequest, Status, OldIrql);
  2958. }
  2959. //
  2960. // Deref for the ref that we took above.
  2961. //
  2962. UC_DEREFERENCE_REQUEST(pRequest);
  2963. }
  2964. pIrp->IoStatus.Status = Status;
  2965. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  2966. }
  2967. return Status;
  2968. } // UcSendEntityBodyIoctl
  2969. /***************************************************************************++
  2970. Routine Description:
  2971. This routine receives a HTTP response
  2972. Arguments:
  2973. pIrp - Supplies a pointer to the IO request packet.
  2974. pIrpSp - Supplies a pointer to the IO stack location to use for this
  2975. request.
  2976. Return Value:
  2977. NTSTATUS - Completion status.
  2978. --***************************************************************************/
  2979. NTSTATUS
  2980. UcReceiveResponseIoctl(
  2981. IN PIRP pIrp,
  2982. IN PIO_STACK_LOCATION pIrpSp
  2983. )
  2984. {
  2985. PHTTP_RECEIVE_RESPONSE_INFO pInfo = NULL;
  2986. NTSTATUS Status = STATUS_SUCCESS;
  2987. PUC_HTTP_REQUEST pRequest = NULL;
  2988. ULONG BytesTaken = 0;
  2989. ASSERT_IOCTL_METHOD(OUT_DIRECT, RECEIVE_RESPONSE);
  2990. do
  2991. {
  2992. if(!IS_SERVER(pIrpSp->FileObject))
  2993. {
  2994. Status = STATUS_INVALID_HANDLE;
  2995. UC_WRITE_TRACE_LOG(
  2996. g_pUcTraceLog,
  2997. UC_ACTION_NEW_RESPONSE,
  2998. NULL,
  2999. NULL,
  3000. NULL,
  3001. UlongToPtr(Status)
  3002. );
  3003. break;
  3004. }
  3005. //
  3006. // Grab the input buffer
  3007. //
  3008. pInfo = (PHTTP_RECEIVE_RESPONSE_INFO) pIrp->AssociatedIrp.SystemBuffer;
  3009. //
  3010. // See if the input buffer is large enough.
  3011. //
  3012. if(
  3013. (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  3014. sizeof(HTTP_RESPONSE)) ||
  3015. (pIrpSp->Parameters.DeviceIoControl.InputBufferLength !=
  3016. sizeof(*pInfo))
  3017. )
  3018. {
  3019. Status = STATUS_BUFFER_TOO_SMALL;
  3020. UC_WRITE_TRACE_LOG(
  3021. g_pUcTraceLog,
  3022. UC_ACTION_NEW_RESPONSE,
  3023. NULL,
  3024. NULL,
  3025. NULL,
  3026. UlongToPtr(Status)
  3027. );
  3028. break;
  3029. }
  3030. //
  3031. // NOTE: We don't have to worry about the RequestID being changed,
  3032. // since it's not a pointer.
  3033. //
  3034. if(HTTP_IS_NULL_ID(&pInfo->RequestID) ||
  3035. pInfo->Flags != 0)
  3036. {
  3037. Status = STATUS_INVALID_PARAMETER;
  3038. UC_WRITE_TRACE_LOG(
  3039. g_pUcTraceLog,
  3040. UC_ACTION_NEW_RESPONSE,
  3041. NULL,
  3042. NULL,
  3043. NULL,
  3044. UlongToPtr(Status)
  3045. );
  3046. break;
  3047. }
  3048. pRequest = (PUC_HTTP_REQUEST) UlGetObjectFromOpaqueId(
  3049. pInfo->RequestID,
  3050. UlOpaqueIdTypeHttpRequest,
  3051. UcReferenceRequest
  3052. );
  3053. if (UC_IS_VALID_HTTP_REQUEST(pRequest) == FALSE)
  3054. {
  3055. Status = STATUS_INVALID_PARAMETER;
  3056. UC_WRITE_TRACE_LOG(
  3057. g_pUcTraceLog,
  3058. UC_ACTION_NEW_RESPONSE,
  3059. NULL,
  3060. NULL,
  3061. NULL,
  3062. UlongToPtr(Status)
  3063. );
  3064. break;
  3065. }
  3066. if(pRequest->pFileObject != pIrpSp->FileObject)
  3067. {
  3068. //
  3069. // Cant allow the app to use someone else's RequestID
  3070. //
  3071. Status = STATUS_INVALID_PARAMETER;
  3072. UC_WRITE_TRACE_LOG(
  3073. g_pUcTraceLog,
  3074. UC_ACTION_NEW_RESPONSE,
  3075. NULL,
  3076. NULL,
  3077. NULL,
  3078. UlongToPtr(Status)
  3079. );
  3080. break;
  3081. }
  3082. BytesTaken = 0;
  3083. Status = UcReceiveHttpResponse(
  3084. pRequest,
  3085. pIrp,
  3086. &BytesTaken
  3087. );
  3088. UC_WRITE_TRACE_LOG(
  3089. g_pUcTraceLog,
  3090. UC_ACTION_NEW_RESPONSE,
  3091. NULL,
  3092. pRequest,
  3093. pIrp,
  3094. UlongToPtr(Status)
  3095. );
  3096. } while(FALSE);
  3097. if(Status == STATUS_SUCCESS)
  3098. {
  3099. pIrp->IoStatus.Status = Status;
  3100. pIrp->IoStatus.Information = (ULONG_PTR) BytesTaken;
  3101. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  3102. }
  3103. else if(Status != STATUS_PENDING)
  3104. {
  3105. if(pRequest)
  3106. {
  3107. UC_DEREFERENCE_REQUEST(pRequest);
  3108. }
  3109. pIrp->IoStatus.Status = Status;
  3110. pIrp->IoStatus.Information = (ULONG_PTR) BytesTaken;
  3111. //
  3112. // If we are not completing the IRP with STATUS_SUCCESS, the IO
  3113. // manager eats the pIrp->IoStatus.Information. But, the user wants
  3114. // to see this information (e.g. when we complete the IRP with
  3115. // STATUS_BUFFER_OVERFLOW, we want to tell the app how much to write.
  3116. //
  3117. // So, we convey this information using the app's pointer. Note that
  3118. // this can be done only if we are completing the IRP synchronously.
  3119. //
  3120. __try
  3121. {
  3122. // This is METHOD_OUT_DIRECT, so the input buffer comes from
  3123. // the IO manager. So, we don't have to worry about the app
  3124. // changing pInfo->pBytesTaken after we've probed it.
  3125. //
  3126. // We still have to probe & access it in a try except block,
  3127. // since this is a user mode pointer.
  3128. if(pInfo && pInfo->pBytesTaken)
  3129. {
  3130. UlProbeForWrite(
  3131. pInfo->pBytesTaken,
  3132. sizeof(ULONG),
  3133. sizeof(ULONG),
  3134. pIrp->RequestorMode
  3135. );
  3136. *pInfo->pBytesTaken = BytesTaken;
  3137. }
  3138. } __except( UL_EXCEPTION_FILTER())
  3139. {
  3140. }
  3141. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  3142. }
  3143. return Status;
  3144. } // UcReceiveResponseIoctl
  3145. /***************************************************************************++
  3146. Routine Description:
  3147. This routine sets per server configuration information
  3148. Arguments:
  3149. pIrp - Supplies a pointer to the IO request packet.
  3150. pIrpSp - Supplies a pointer to the IO stack location to use for this
  3151. request.
  3152. Return Value:
  3153. NTSTATUS - Completion status.
  3154. --***************************************************************************/
  3155. NTSTATUS
  3156. UcSetServerContextInformationIoctl(
  3157. IN PIRP pIrp,
  3158. IN PIO_STACK_LOCATION IrpSp
  3159. )
  3160. {
  3161. NTSTATUS Status = STATUS_SUCCESS;
  3162. PUC_PROCESS_SERVER_INFORMATION pServerInfo;
  3163. PHTTP_SERVER_CONTEXT_INFORMATION pInfo;
  3164. ASSERT_IOCTL_METHOD(IN_DIRECT, SET_SERVER_CONTEXT_INFORMATION);
  3165. do
  3166. {
  3167. if(!IS_SERVER(IrpSp->FileObject))
  3168. {
  3169. Status = STATUS_INVALID_HANDLE;
  3170. break;
  3171. }
  3172. //
  3173. // Pull out the connection information from the Irp, make sure it is
  3174. // valid.
  3175. //
  3176. pServerInfo = (PUC_PROCESS_SERVER_INFORMATION)
  3177. IrpSp->FileObject->FsContext;
  3178. ASSERT( IS_VALID_SERVER_INFORMATION(pServerInfo) );
  3179. //
  3180. // See if the input buffer is large enough.
  3181. //
  3182. if( IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  3183. sizeof(*pInfo))
  3184. {
  3185. Status = STATUS_BUFFER_TOO_SMALL;
  3186. break;
  3187. }
  3188. pInfo = (PHTTP_SERVER_CONTEXT_INFORMATION)
  3189. pIrp->AssociatedIrp.SystemBuffer;
  3190. Status = UcSetServerContextInformation(
  3191. pServerInfo,
  3192. pInfo->ConfigID,
  3193. pInfo->pInputBuffer,
  3194. pInfo->InputBufferLength,
  3195. pIrp
  3196. );
  3197. } while(FALSE);
  3198. ASSERT(STATUS_PENDING != Status);
  3199. pIrp->IoStatus.Status = Status;
  3200. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  3201. return Status;
  3202. } // UcSetServerContextInformationIoctl
  3203. /***************************************************************************++
  3204. Routine Description:
  3205. This routine queries per server configuration information
  3206. Arguments:
  3207. pIrp - Supplies a pointer to the IO request packet.
  3208. pIrpSp - Supplies a pointer to the IO stack location to use for this
  3209. request.
  3210. Return Value:
  3211. NTSTATUS - Completion status.
  3212. --***************************************************************************/
  3213. NTSTATUS
  3214. UcQueryServerContextInformationIoctl(
  3215. IN PIRP pIrp,
  3216. IN PIO_STACK_LOCATION IrpSp
  3217. )
  3218. {
  3219. NTSTATUS Status = STATUS_SUCCESS;
  3220. PUC_PROCESS_SERVER_INFORMATION pServerInfo;
  3221. PHTTP_SERVER_CONTEXT_INFORMATION pInfo = NULL;
  3222. PVOID pAppBase, pMdlBuffer;
  3223. ULONG Length = 0;
  3224. ASSERT_IOCTL_METHOD(OUT_DIRECT, QUERY_SERVER_CONTEXT_INFORMATION);
  3225. do
  3226. {
  3227. if(!IS_SERVER(IrpSp->FileObject))
  3228. {
  3229. Status = STATUS_INVALID_HANDLE;
  3230. break;
  3231. }
  3232. //
  3233. // Pull out the connection information from the Irp, make sure it is
  3234. // valid.
  3235. //
  3236. pServerInfo = (PUC_PROCESS_SERVER_INFORMATION)
  3237. IrpSp->FileObject->FsContext;
  3238. ASSERT( IS_VALID_SERVER_INFORMATION(pServerInfo) );
  3239. //
  3240. // See if the input buffer is large enough.
  3241. //
  3242. if( IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  3243. sizeof(*pInfo))
  3244. {
  3245. Status = STATUS_BUFFER_TOO_SMALL;
  3246. break;
  3247. }
  3248. //
  3249. // Ensure that the output buffer looks good.
  3250. //
  3251. if(!pIrp->MdlAddress)
  3252. {
  3253. Status = STATUS_INVALID_PARAMETER;
  3254. break;
  3255. }
  3256. pInfo = (PHTTP_SERVER_CONTEXT_INFORMATION)
  3257. pIrp->AssociatedIrp.SystemBuffer;
  3258. pMdlBuffer = MmGetSystemAddressForMdlSafe(
  3259. pIrp->MdlAddress,
  3260. LowPagePriority
  3261. );
  3262. if (pMdlBuffer == NULL)
  3263. {
  3264. Status = STATUS_INSUFFICIENT_RESOURCES;
  3265. break;
  3266. }
  3267. //
  3268. // Make sure that the output buffer is ULONG aligned.
  3269. //
  3270. if(pMdlBuffer != ALIGN_UP_POINTER(pMdlBuffer, ULONG))
  3271. {
  3272. Status = STATUS_DATATYPE_MISALIGNMENT_ERROR;
  3273. break;
  3274. }
  3275. pAppBase = (PSTR) MmGetMdlVirtualAddress(pIrp->MdlAddress);
  3276. Length = 0;
  3277. Status = UcQueryServerContextInformation(
  3278. pServerInfo,
  3279. pInfo->ConfigID,
  3280. pMdlBuffer,
  3281. IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  3282. &Length,
  3283. pAppBase
  3284. );
  3285. } while(FALSE);
  3286. ASSERT(STATUS_PENDING != Status);
  3287. if(Status != STATUS_SUCCESS)
  3288. {
  3289. //
  3290. // If we are not completing the IRP with STATUS_SUCCESS, the IO
  3291. // manager eats the pIrp->IoStatus.Information. But, the user wants
  3292. // to see this information (e.g. when we complete the IRP with
  3293. // STATUS_BUFFER_OVERFLOW, we want to tell the app how much to write.
  3294. //
  3295. // So, we convey this information using the app's pointer. Note that
  3296. // this can be done only if we are completing the IRP synchronously.
  3297. //
  3298. __try
  3299. {
  3300. // This is METHOD_OUT_DIRECT, so the input buffer comes from
  3301. // the IO manager. So, we don't have to worry about the app
  3302. // changing pInfo->pBytesTaken after we've probed it.
  3303. //
  3304. // We still have to probe & access it in a try except block,
  3305. // since this is a user mode pointer.
  3306. if(pInfo && pInfo->pBytesTaken)
  3307. {
  3308. UlProbeForWrite(
  3309. pInfo->pBytesTaken,
  3310. sizeof(ULONG),
  3311. sizeof(ULONG),
  3312. pIrp->RequestorMode
  3313. );
  3314. *pInfo->pBytesTaken = Length;
  3315. }
  3316. } __except( UL_EXCEPTION_FILTER())
  3317. {
  3318. }
  3319. }
  3320. pIrp->IoStatus.Status = Status;
  3321. pIrp->IoStatus.Information = (ULONG_PTR) Length;
  3322. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  3323. return Status;
  3324. } // UcQueryServerContextInformationIoctl
  3325. /***************************************************************************++
  3326. Routine Description:
  3327. This routine sends a HTTP request
  3328. Arguments:
  3329. pIrp - Supplies a pointer to the IO request packet.
  3330. pIrpSp - Supplies a pointer to the IO stack location to use for this
  3331. request.
  3332. Return Value:
  3333. NTSTATUS - Completion status.
  3334. --***************************************************************************/
  3335. NTSTATUS
  3336. UcSendRequestIoctl(
  3337. IN PIRP pIrp,
  3338. IN PIO_STACK_LOCATION IrpSp
  3339. )
  3340. {
  3341. NTSTATUS Status = STATUS_SUCCESS;
  3342. PHTTP_SEND_REQUEST_INPUT_INFO pHttpSendRequest = NULL;
  3343. PUC_HTTP_REQUEST pHttpInternalRequest = 0;
  3344. PUC_PROCESS_SERVER_INFORMATION pServerInfo;
  3345. ULONG BytesTaken = 0;
  3346. ASSERT_IOCTL_METHOD(OUT_DIRECT, SEND_REQUEST);
  3347. do
  3348. {
  3349. if(!IS_SERVER(IrpSp->FileObject))
  3350. {
  3351. Status = STATUS_INVALID_HANDLE;
  3352. UC_WRITE_TRACE_LOG(
  3353. g_pUcTraceLog,
  3354. UC_ACTION_REQUEST_NEW,
  3355. NULL,
  3356. NULL,
  3357. pIrp,
  3358. UlongToPtr(Status)
  3359. );
  3360. break;
  3361. }
  3362. //
  3363. // Pull out the connection information from the Irp, make sure it is
  3364. // valid.
  3365. //
  3366. // IrpSp->FileObject->FsContext;
  3367. //
  3368. pServerInfo = (PUC_PROCESS_SERVER_INFORMATION)
  3369. IrpSp->FileObject->FsContext;
  3370. ASSERT( IS_VALID_SERVER_INFORMATION(pServerInfo) );
  3371. //
  3372. // See if the input buffer is large enough.
  3373. //
  3374. if( IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  3375. sizeof(*pHttpSendRequest))
  3376. {
  3377. Status = STATUS_BUFFER_TOO_SMALL;
  3378. UC_WRITE_TRACE_LOG(
  3379. g_pUcTraceLog,
  3380. UC_ACTION_REQUEST_NEW,
  3381. NULL,
  3382. NULL,
  3383. pIrp,
  3384. UlongToPtr(Status)
  3385. );
  3386. break;
  3387. }
  3388. pHttpSendRequest = (PHTTP_SEND_REQUEST_INPUT_INFO)
  3389. pIrp->AssociatedIrp.SystemBuffer;
  3390. if(NULL == pHttpSendRequest->pHttpRequest)
  3391. {
  3392. Status = STATUS_INVALID_PARAMETER;
  3393. UC_WRITE_TRACE_LOG(
  3394. g_pUcTraceLog,
  3395. UC_ACTION_REQUEST_NEW,
  3396. NULL,
  3397. NULL,
  3398. pIrp,
  3399. UlongToPtr(Status)
  3400. );
  3401. break;
  3402. }
  3403. //
  3404. // Make sure that the SEND_REQUEST_FLAGS are valid.
  3405. //
  3406. if(pHttpSendRequest->HttpRequestFlags & (~HTTP_SEND_REQUEST_FLAG_VALID))
  3407. {
  3408. Status = STATUS_INVALID_PARAMETER;
  3409. UC_WRITE_TRACE_LOG(
  3410. g_pUcTraceLog,
  3411. UC_ACTION_REQUEST_NEW,
  3412. NULL,
  3413. NULL,
  3414. pIrp,
  3415. UlongToPtr(Status)
  3416. );
  3417. break;
  3418. }
  3419. BytesTaken = 0;
  3420. Status = UcCaptureHttpRequest(pServerInfo,
  3421. pHttpSendRequest,
  3422. pIrp,
  3423. IrpSp,
  3424. &pHttpInternalRequest,
  3425. &BytesTaken
  3426. );
  3427. if(!NT_SUCCESS(Status))
  3428. {
  3429. UC_WRITE_TRACE_LOG(
  3430. g_pUcTraceLog,
  3431. UC_ACTION_REQUEST_NEW,
  3432. NULL,
  3433. NULL,
  3434. pIrp,
  3435. UlongToPtr(Status)
  3436. );
  3437. break;
  3438. }
  3439. //
  3440. // Save the captured request in the IRP.
  3441. //
  3442. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer =
  3443. pHttpInternalRequest;
  3444. UC_WRITE_TRACE_LOG(
  3445. g_pUcTraceLog,
  3446. UC_ACTION_REQUEST_NEW,
  3447. NULL,
  3448. pHttpInternalRequest,
  3449. pIrp,
  3450. UlongToPtr(Status)
  3451. );
  3452. //
  3453. // We have to pin the request down to a connection regardless of
  3454. // whether we are going to send it or not. We need to do this to
  3455. // maintain the order in which the user passes requests to the driver.
  3456. //
  3457. Status = UcSendRequest(pServerInfo, pHttpInternalRequest);
  3458. } while(FALSE);
  3459. if (Status == STATUS_SUCCESS)
  3460. {
  3461. ASSERT(pHttpInternalRequest);
  3462. pIrp->IoStatus.Status = Status;
  3463. // For the IRP.
  3464. UC_DEREFERENCE_REQUEST(pHttpInternalRequest);
  3465. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  3466. }
  3467. else if (Status != STATUS_PENDING)
  3468. {
  3469. if(pHttpInternalRequest)
  3470. {
  3471. // For the IRP.
  3472. UC_DEREFERENCE_REQUEST(pHttpInternalRequest);
  3473. UcFreeSendMdls(pHttpInternalRequest->pMdlHead);
  3474. //
  3475. // We don't need the Request ID
  3476. //
  3477. if(!HTTP_IS_NULL_ID(&pHttpInternalRequest->RequestId))
  3478. {
  3479. UlFreeOpaqueId(
  3480. pHttpInternalRequest->RequestId,
  3481. UlOpaqueIdTypeHttpRequest
  3482. );
  3483. HTTP_SET_NULL_ID(&pHttpInternalRequest->RequestId);
  3484. UC_DEREFERENCE_REQUEST(pHttpInternalRequest);
  3485. }
  3486. UC_DEREFERENCE_REQUEST(pHttpInternalRequest);
  3487. }
  3488. pIrp->IoStatus.Status = Status;
  3489. pIrp->IoStatus.Information = (ULONG_PTR) BytesTaken;
  3490. //
  3491. // If we are not completing the IRP with STATUS_SUCCESS, the IO
  3492. // manager eats the pIrp->IoStatus.Information. But, the user wants
  3493. // to see this information (e.g. when we complete the IRP with
  3494. // STATUS_BUFFER_OVERFLOW, we want to tell the app how much to write.
  3495. //
  3496. // So, we convey this information using the app's pointer. Note that
  3497. // this can be done only if we are completing the IRP synchronously.
  3498. //
  3499. __try
  3500. {
  3501. // This is METHOD_OUT_DIRECT, so the input buffer comes from
  3502. // the IO manager. So, we don't have to worry about the app
  3503. // changing pHttpSendRequest->pBytesTaken after we've probed it.
  3504. //
  3505. // We still have to probe & access it in a try except block,
  3506. // since this is a user mode pointer.
  3507. if(pHttpSendRequest && pHttpSendRequest->pBytesTaken)
  3508. {
  3509. UlProbeForWrite(
  3510. pHttpSendRequest->pBytesTaken,
  3511. sizeof(ULONG),
  3512. sizeof(ULONG),
  3513. pIrp->RequestorMode
  3514. );
  3515. *pHttpSendRequest->pBytesTaken = BytesTaken;
  3516. }
  3517. } __except( UL_EXCEPTION_FILTER())
  3518. {
  3519. }
  3520. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  3521. }
  3522. return Status;
  3523. } // UcSendRequestIoctl
  3524. /***************************************************************************++
  3525. Routine Description:
  3526. This routine cancels a HTTP request
  3527. Arguments:
  3528. pIrp - Supplies a pointer to the IO request packet.
  3529. pIrpSp - Supplies a pointer to the IO stack location to use for this
  3530. request.
  3531. Return Value:
  3532. NTSTATUS - Completion status.
  3533. --***************************************************************************/
  3534. NTSTATUS
  3535. UcCancelRequestIoctl(
  3536. IN PIRP pIrp,
  3537. IN PIO_STACK_LOCATION pIrpSp
  3538. )
  3539. {
  3540. NTSTATUS Status = STATUS_SUCCESS;
  3541. PHTTP_RECEIVE_RESPONSE_INFO pInfo;
  3542. PUC_HTTP_REQUEST pRequest = NULL;
  3543. PUC_PROCESS_SERVER_INFORMATION pServerInfo;
  3544. KIRQL OldIrql;
  3545. ASSERT_IOCTL_METHOD(BUFFERED, CANCEL_REQUEST);
  3546. do
  3547. {
  3548. if(!IS_SERVER(pIrpSp->FileObject))
  3549. {
  3550. Status = STATUS_INVALID_HANDLE;
  3551. UC_WRITE_TRACE_LOG(
  3552. g_pUcTraceLog,
  3553. UC_ACTION_REQUEST_CANCELLED,
  3554. NULL,
  3555. NULL,
  3556. pIrp,
  3557. UlongToPtr(Status)
  3558. );
  3559. break;
  3560. }
  3561. //
  3562. // Pull out the connection information from the Irp, make sure it is
  3563. // valid.
  3564. //
  3565. // IrpSp->FileObject->FsContext;
  3566. //
  3567. pServerInfo = (PUC_PROCESS_SERVER_INFORMATION)
  3568. pIrpSp->FileObject->FsContext;
  3569. ASSERT( IS_VALID_SERVER_INFORMATION(pServerInfo) );
  3570. //
  3571. // Grab the input buffer
  3572. //
  3573. pInfo = (PHTTP_RECEIVE_RESPONSE_INFO) pIrp->AssociatedIrp.SystemBuffer;
  3574. //
  3575. // See if the input buffer is large enough.
  3576. //
  3577. if(
  3578. (pIrpSp->Parameters.DeviceIoControl.InputBufferLength !=
  3579. sizeof(*pInfo))
  3580. )
  3581. {
  3582. Status = STATUS_BUFFER_TOO_SMALL;
  3583. UC_WRITE_TRACE_LOG(
  3584. g_pUcTraceLog,
  3585. UC_ACTION_REQUEST_CANCELLED,
  3586. NULL,
  3587. NULL,
  3588. NULL,
  3589. UlongToPtr(Status)
  3590. );
  3591. break;
  3592. }
  3593. if(HTTP_IS_NULL_ID(&pInfo->RequestID) ||
  3594. pInfo->Flags != 0)
  3595. {
  3596. Status = STATUS_INVALID_PARAMETER;
  3597. UC_WRITE_TRACE_LOG(
  3598. g_pUcTraceLog,
  3599. UC_ACTION_REQUEST_CANCELLED,
  3600. NULL,
  3601. NULL,
  3602. NULL,
  3603. UlongToPtr(Status)
  3604. );
  3605. break;
  3606. }
  3607. pRequest = (PUC_HTTP_REQUEST) UlGetObjectFromOpaqueId(
  3608. pInfo->RequestID,
  3609. UlOpaqueIdTypeHttpRequest,
  3610. UcReferenceRequest
  3611. );
  3612. if (UC_IS_VALID_HTTP_REQUEST(pRequest) == FALSE)
  3613. {
  3614. Status = STATUS_INVALID_PARAMETER;
  3615. UC_WRITE_TRACE_LOG(
  3616. g_pUcTraceLog,
  3617. UC_ACTION_REQUEST_CANCELLED,
  3618. NULL,
  3619. NULL,
  3620. NULL,
  3621. UlongToPtr(Status)
  3622. );
  3623. break;
  3624. }
  3625. if(pRequest->pFileObject != pIrpSp->FileObject)
  3626. {
  3627. //
  3628. // Cant allow the app to use someone else's RequestID
  3629. //
  3630. Status = STATUS_INVALID_PARAMETER;
  3631. UC_WRITE_TRACE_LOG(
  3632. g_pUcTraceLog,
  3633. UC_ACTION_ENTITY_NEW,
  3634. pRequest,
  3635. NULL,
  3636. NULL,
  3637. UlongToPtr(Status)
  3638. );
  3639. break;
  3640. }
  3641. UlAcquireSpinLock(&pRequest->pConnection->SpinLock, &OldIrql);
  3642. UcFailRequest(pRequest, STATUS_CANCELLED, OldIrql);
  3643. Status = STATUS_SUCCESS;
  3644. } while(FALSE);
  3645. if (Status == STATUS_SUCCESS)
  3646. {
  3647. UC_DEREFERENCE_REQUEST(pRequest);
  3648. pIrp->IoStatus.Status = Status;
  3649. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  3650. }
  3651. else
  3652. {
  3653. ASSERT(Status != STATUS_PENDING);
  3654. if(pRequest)
  3655. {
  3656. UC_DEREFERENCE_REQUEST(pRequest);
  3657. }
  3658. pIrp->IoStatus.Status = Status;
  3659. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  3660. }
  3661. return Status;
  3662. } // UcCancelRequestIoctl