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

709 lines
18 KiB

  1. /*++
  2. Copyright (c) 1998-2001 Microsoft Corporation
  3. Module Name:
  4. internal.c
  5. Abstract:
  6. User-mode interface to HTTP.SYS.
  7. Author:
  8. Keith Moore (keithmo) 15-Dec-1998
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. //
  13. // Private definitions
  14. //
  15. typedef struct _CACHED_EVENT
  16. {
  17. SINGLE_LIST_ENTRY ListEntry;
  18. HANDLE EventHandle;
  19. } CACHED_EVENT, *PCACHED_EVENT;
  20. //
  21. // Private globals
  22. //
  23. SLIST_HEADER CachedEventList;
  24. //
  25. // Private macros.
  26. //
  27. #define EA_BUFFER_LENGTH \
  28. ( sizeof(FILE_FULL_EA_INFORMATION) + \
  29. HTTP_OPEN_PACKET_NAME_LENGTH + \
  30. sizeof(HTTP_OPEN_PACKET) )
  31. //
  32. // Private prototypes.
  33. //
  34. NTSTATUS
  35. HttpApiAcquireCachedEvent(
  36. OUT CACHED_EVENT ** ppCachedEvent
  37. );
  38. VOID
  39. HttpApiReleaseCachedEvent(
  40. IN CACHED_EVENT * pCachedEvent
  41. );
  42. //
  43. // Public functions.
  44. //
  45. /***************************************************************************++
  46. Routine Description:
  47. Synchronous wrapper around NtDeviceIoControlFile().
  48. Arguments:
  49. FileHandle - Supplies a handle to the file on which the service is
  50. being performed.
  51. IoControlCode - Subfunction code to determine exactly what operation
  52. is being performed.
  53. pInputBuffer - Optionally supplies an input buffer to be passed to the
  54. device driver. Whether or not the buffer is actually optional is
  55. dependent on the IoControlCode.
  56. InputBufferLength - Length of the pInputBuffer in bytes.
  57. pOutputBuffer - Optionally supplies an output buffer to receive
  58. information from the device driver. Whether or not the buffer is
  59. actually optional is dependent on the IoControlCode.
  60. OutputBufferLength - Length of the pOutputBuffer in bytes.
  61. pBytesTransferred - Optionally receives the number of bytes transferred.
  62. Return Value:
  63. NTSTATUS - Completion status.
  64. --***************************************************************************/
  65. NTSTATUS
  66. HttpApiSynchronousDeviceControl(
  67. IN HANDLE FileHandle,
  68. IN ULONG IoControlCode,
  69. IN PVOID pInputBuffer OPTIONAL,
  70. IN ULONG InputBufferLength,
  71. OUT PVOID pOutputBuffer OPTIONAL,
  72. IN ULONG OutputBufferLength,
  73. OUT PULONG pBytesTransferred OPTIONAL
  74. )
  75. {
  76. NTSTATUS status;
  77. IO_STATUS_BLOCK ioStatusBlock;
  78. CACHED_EVENT * pCachedEvent;
  79. LARGE_INTEGER timeout;
  80. //
  81. // Try to snag an event object.
  82. //
  83. status = HttpApiAcquireCachedEvent( &pCachedEvent );
  84. if (NT_SUCCESS(status))
  85. {
  86. ASSERT( pCachedEvent != NULL );
  87. //
  88. // Make the call.
  89. //
  90. status = NtDeviceIoControlFile(
  91. FileHandle, // FileHandle
  92. pCachedEvent->EventHandle, // Event
  93. NULL, // ApcRoutine
  94. NULL, // ApcContext
  95. &ioStatusBlock, // IoStatusBlock
  96. IoControlCode, // IoControlCode
  97. pInputBuffer, // InputBuffer
  98. InputBufferLength, // InputBufferLength
  99. pOutputBuffer, // OutputBuffer
  100. OutputBufferLength // OutputBufferLength
  101. );
  102. if (status == STATUS_PENDING)
  103. {
  104. //
  105. // Wait for it to complete.
  106. //
  107. timeout.LowPart = 0xFFFFFFFF;
  108. timeout.HighPart = 0x7FFFFFFF;
  109. status = NtWaitForSingleObject( pCachedEvent->EventHandle,
  110. FALSE,
  111. &timeout );
  112. ASSERT( status == STATUS_SUCCESS );
  113. status = ioStatusBlock.Status;
  114. }
  115. //
  116. // If the call didn't fail and the caller wants the number
  117. // of bytes transferred, grab the value from the I/O status
  118. // block & return it.
  119. //
  120. if (!NT_ERROR(status) && pBytesTransferred != NULL)
  121. {
  122. *pBytesTransferred = (ULONG)ioStatusBlock.Information;
  123. }
  124. //
  125. // Release the cached event object we acquired above.
  126. //
  127. HttpApiReleaseCachedEvent( pCachedEvent );
  128. }
  129. return status;
  130. } // HttpApiSynchronousDeviceControl
  131. /***************************************************************************++
  132. Routine Description:
  133. Overlapped wrapper around NtDeviceIoControlFile().
  134. Arguments:
  135. FileHandle - Supplies a handle to the file on which the service is
  136. being performed.
  137. pOverlapped - Supplies an OVERLAPPED structure.
  138. IoControlCode - Subfunction code to determine exactly what operation
  139. is being performed.
  140. pInputBuffer - Optionally supplies an input buffer to be passed to the
  141. device driver. Whether or not the buffer is actually optional is
  142. dependent on the IoControlCode.
  143. InputBufferLength - Length of the pInputBuffer in bytes.
  144. pOutputBuffer - Optionally supplies an output buffer to receive
  145. information from the device driver. Whether or not the buffer is
  146. actually optional is dependent on the IoControlCode.
  147. OutputBufferLength - Length of the pOutputBuffer in bytes.
  148. pBytesTransferred - Optionally receives the number of bytes transferred.
  149. Return Value:
  150. NTSTATUS - Completion status.
  151. --***************************************************************************/
  152. NTSTATUS
  153. HttpApiOverlappedDeviceControl(
  154. IN HANDLE FileHandle,
  155. IN OUT LPOVERLAPPED pOverlapped,
  156. IN ULONG IoControlCode,
  157. IN PVOID pInputBuffer OPTIONAL,
  158. IN ULONG InputBufferLength,
  159. OUT PVOID pOutputBuffer OPTIONAL,
  160. IN ULONG OutputBufferLength,
  161. OUT PULONG pBytesTransferred OPTIONAL
  162. )
  163. {
  164. NTSTATUS status;
  165. //
  166. // Overlapped I/O gets a little more interesting. We'll strive to be
  167. // compatible with NT's KERNEL32 implementation. See DeviceIoControl()
  168. // in \\rastaman\ntwin\src\base\client\filehops.c for the gory details.
  169. //
  170. OVERLAPPED_TO_IO_STATUS(pOverlapped)->Status = STATUS_PENDING;
  171. status = NtDeviceIoControlFile(
  172. FileHandle, // FileHandle
  173. pOverlapped->hEvent, // Event
  174. NULL, // ApcRoutine
  175. (ULONG_PTR)pOverlapped->hEvent & 1 // ApcContext
  176. ? NULL : pOverlapped,
  177. OVERLAPPED_TO_IO_STATUS(pOverlapped), // IoStatusBlock
  178. IoControlCode, // IoControlCode
  179. pInputBuffer, // InputBuffer
  180. InputBufferLength, // InputBufferLength
  181. pOutputBuffer, // OutputBuffer
  182. OutputBufferLength // OutputBufferLength
  183. );
  184. //
  185. // If the call didn't fail or pend and the caller wants the number of
  186. // bytes transferred, grab the value from the I/O status block &
  187. // return it.
  188. //
  189. if (status == STATUS_SUCCESS)
  190. {
  191. if (pBytesTransferred)
  192. {
  193. *pBytesTransferred =
  194. (ULONG)OVERLAPPED_TO_IO_STATUS(pOverlapped)->Information;
  195. }
  196. status = STATUS_PENDING;
  197. }
  198. return status;
  199. } // HttpApiOverlappedDeviceControl
  200. /***************************************************************************++
  201. Routine Description:
  202. Initializes the event object cache.
  203. Return Value:
  204. ULONG - Completion status.
  205. --***************************************************************************/
  206. ULONG
  207. HttpApiInitializeEventCache(
  208. VOID
  209. )
  210. {
  211. RtlInitializeSListHead( &CachedEventList );
  212. return NO_ERROR;
  213. } // HttpApiInitializeEventCache
  214. /***************************************************************************++
  215. Routine Description:
  216. Terminates the event object cache.
  217. Return Value:
  218. ULONG - Completion status.
  219. --***************************************************************************/
  220. ULONG
  221. HttpApiTerminateEventCache(
  222. VOID
  223. )
  224. {
  225. CACHED_EVENT * pCachedEvent;
  226. PSINGLE_LIST_ENTRY Entry;
  227. for ( ;; )
  228. {
  229. Entry = RtlInterlockedPopEntrySList( &CachedEventList );
  230. if (Entry == NULL)
  231. {
  232. break;
  233. }
  234. pCachedEvent = CONTAINING_RECORD( Entry, CACHED_EVENT, ListEntry );
  235. NtClose( pCachedEvent->EventHandle );
  236. FREE_MEM( pCachedEvent );
  237. }
  238. return NO_ERROR;
  239. } // HttpApiTerminateEventCache
  240. /***************************************************************************++
  241. Routine Description:
  242. This routine attempts to start UL.SYS.
  243. Return Value:
  244. BOOLEAN - TRUE if successful, FALSE otherwise.
  245. --***************************************************************************/
  246. BOOLEAN
  247. HttpApiTryToStartDriver(
  248. VOID
  249. )
  250. {
  251. BOOLEAN result;
  252. SC_HANDLE scHandle;
  253. SC_HANDLE svcHandle;
  254. result = FALSE; // until proven otherwise...
  255. //
  256. // Open the service controller.
  257. //
  258. scHandle = OpenSCManagerW(
  259. NULL, // lpMachineName
  260. NULL, // lpDatabaseName
  261. SC_MANAGER_ALL_ACCESS // dwDesiredAccess
  262. );
  263. if (scHandle != NULL)
  264. {
  265. //
  266. // Try to open the UL service.
  267. //
  268. svcHandle = OpenServiceW(
  269. scHandle, // hSCManager
  270. HTTP_SERVICE_NAME, // lpServiceName
  271. SERVICE_ALL_ACCESS // dwDesiredAccess
  272. );
  273. if (svcHandle != NULL)
  274. {
  275. //
  276. // Try to start it.
  277. //
  278. if (StartService( svcHandle, 0, NULL))
  279. {
  280. result = TRUE;
  281. }
  282. CloseServiceHandle( svcHandle );
  283. }
  284. CloseServiceHandle( scHandle );
  285. }
  286. return result;
  287. } // HttpApiTryToStartDriver
  288. //
  289. // Private functions.
  290. //
  291. /***************************************************************************++
  292. Routine Description:
  293. Helper routine for opening a UL.SYS handle.
  294. Arguments:
  295. pHandle - Receives a handle if successful.
  296. DesiredAccess - Supplies the types of access requested to the file.
  297. HandleType - one of Filter, ControlChannel, or AppPool
  298. pObjectName - Optionally supplies the name of the application pool
  299. to create/open.
  300. Options - Supplies zero or more HTTP_OPTION_* flags.
  301. CreateDisposition - Supplies the creation disposition for the new
  302. object.
  303. pSecurityAttributes - Optionally supplies security attributes for
  304. the newly created application pool. Ignored if opening a
  305. control channel.
  306. Return Value:
  307. NTSTATUS - Completion status.
  308. --***************************************************************************/
  309. NTSTATUS
  310. HttpApiOpenDriverHelper(
  311. OUT PHANDLE pHandle,
  312. IN ACCESS_MASK DesiredAccess,
  313. IN HTTPAPI_HANDLE_TYPE HandleType,
  314. IN PCWSTR pObjectName OPTIONAL,
  315. IN ULONG Options,
  316. IN ULONG CreateDisposition,
  317. IN PSECURITY_ATTRIBUTES pSecurityAttributes OPTIONAL
  318. )
  319. {
  320. NTSTATUS status;
  321. OBJECT_ATTRIBUTES objectAttributes;
  322. UNICODE_STRING deviceName;
  323. IO_STATUS_BLOCK ioStatusBlock;
  324. ULONG shareAccess;
  325. ULONG createOptions;
  326. PFILE_FULL_EA_INFORMATION pEaBuffer;
  327. PHTTP_OPEN_PACKET pOpenPacket;
  328. WCHAR deviceNameBuffer[MAX_PATH];
  329. UCHAR rawEaBuffer[EA_BUFFER_LENGTH];
  330. //
  331. // Validate the parameters.
  332. //
  333. if ((pHandle == NULL) ||
  334. (Options & ~HTTP_OPTION_VALID))
  335. {
  336. return STATUS_INVALID_PARAMETER;
  337. }
  338. if ((HandleType != HttpApiControlChannelHandleType) &&
  339. (HandleType != HttpApiFilterChannelHandleType) &&
  340. (HandleType != HttpApiAppPoolHandleType))
  341. {
  342. return STATUS_INVALID_PARAMETER;
  343. }
  344. //
  345. // Build the open packet.
  346. //
  347. pEaBuffer = (PFILE_FULL_EA_INFORMATION)rawEaBuffer;
  348. pEaBuffer->NextEntryOffset = 0;
  349. pEaBuffer->Flags = 0;
  350. pEaBuffer->EaNameLength = HTTP_OPEN_PACKET_NAME_LENGTH;
  351. pEaBuffer->EaValueLength = sizeof(*pOpenPacket);
  352. RtlCopyMemory(
  353. pEaBuffer->EaName,
  354. HTTP_OPEN_PACKET_NAME,
  355. HTTP_OPEN_PACKET_NAME_LENGTH + 1
  356. );
  357. pOpenPacket =
  358. (PHTTP_OPEN_PACKET)( pEaBuffer->EaName + pEaBuffer->EaNameLength + 1 );
  359. pOpenPacket->MajorVersion = HTTP_INTERFACE_VERSION_MAJOR;
  360. pOpenPacket->MinorVersion = HTTP_INTERFACE_VERSION_MINOR;
  361. //
  362. // Build the device name.
  363. //
  364. if (HandleType == HttpApiControlChannelHandleType)
  365. {
  366. //
  367. // It's a control channel, so just use the appropriate device name.
  368. //
  369. wcscpy( deviceNameBuffer, HTTP_CONTROL_DEVICE_NAME );
  370. }
  371. else
  372. {
  373. if (HandleType == HttpApiFilterChannelHandleType)
  374. {
  375. //
  376. // It's a fitler channel, so start with the appropriate
  377. // device name.
  378. //
  379. wcscpy( deviceNameBuffer, HTTP_FILTER_DEVICE_NAME );
  380. }
  381. else
  382. {
  383. ASSERT(HandleType == HttpApiAppPoolHandleType);
  384. //
  385. // It's an app pool, so start with the appropriate device name.
  386. //
  387. wcscpy( deviceNameBuffer, HTTP_APP_POOL_DEVICE_NAME );
  388. //
  389. // Set WRITE_OWNER in DesiredAccess if AppPool is a controller.
  390. //
  391. if ((Options & HTTP_OPTION_CONTROLLER))
  392. {
  393. DesiredAccess |= WRITE_OWNER;
  394. }
  395. }
  396. if (pObjectName != NULL )
  397. {
  398. //
  399. // It's a named object, so append a slash and the name,
  400. // but first check to ensure we don't overrun our buffer.
  401. //
  402. if ((wcslen(deviceNameBuffer) + wcslen(pObjectName) + 2)
  403. > DIMENSION(deviceNameBuffer))
  404. {
  405. status = STATUS_INVALID_PARAMETER;
  406. goto complete;
  407. }
  408. wcscat( deviceNameBuffer, L"\\" );
  409. wcscat( deviceNameBuffer, pObjectName );
  410. }
  411. }
  412. //
  413. // Determine the share access and create options based on the
  414. // Flags parameter.
  415. //
  416. shareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
  417. createOptions = 0;
  418. if ((Options & HTTP_OPTION_OVERLAPPED) == 0)
  419. {
  420. createOptions |= FILE_SYNCHRONOUS_IO_NONALERT;
  421. }
  422. //
  423. // Build the object attributes.
  424. //
  425. RtlInitUnicodeString( &deviceName, deviceNameBuffer );
  426. InitializeObjectAttributes(
  427. &objectAttributes, // ObjectAttributes
  428. &deviceName, // ObjectName
  429. OBJ_CASE_INSENSITIVE, // Attributes
  430. NULL, // RootDirectory
  431. NULL, // SecurityDescriptor
  432. );
  433. if (pSecurityAttributes != NULL)
  434. {
  435. objectAttributes.SecurityDescriptor =
  436. pSecurityAttributes->lpSecurityDescriptor;
  437. if (pSecurityAttributes->bInheritHandle)
  438. {
  439. objectAttributes.Attributes |= OBJ_INHERIT;
  440. }
  441. }
  442. //
  443. // Open the UL device.
  444. //
  445. status = NtCreateFile(
  446. pHandle, // FileHandle
  447. DesiredAccess, // DesiredAccess
  448. &objectAttributes, // ObjectAttributes
  449. &ioStatusBlock, // IoStatusBlock
  450. NULL, // AllocationSize
  451. 0, // FileAttributes
  452. shareAccess, // ShareAccess
  453. CreateDisposition, // CreateDisposition
  454. createOptions, // CreateOptions
  455. pEaBuffer, // EaBuffer
  456. EA_BUFFER_LENGTH // EaLength
  457. );
  458. complete:
  459. if (!NT_SUCCESS(status))
  460. {
  461. *pHandle = NULL;
  462. }
  463. return status;
  464. } // HttpApiOpenDriverHelper
  465. /***************************************************************************++
  466. Routine Description:
  467. Acquires a short-term event from the global event cache. This event
  468. object may only be used for pseudo-synchronous I/O.
  469. Arguments:
  470. ppCachedEvent - Receives pointer to cached event structure
  471. Return Value:
  472. NTSTATUS - Completion status.
  473. --***************************************************************************/
  474. NTSTATUS
  475. HttpApiAcquireCachedEvent(
  476. OUT CACHED_EVENT ** ppCachedEvent
  477. )
  478. {
  479. PSINGLE_LIST_ENTRY Entry;
  480. NTSTATUS status;
  481. CACHED_EVENT * pCachedEvent;
  482. Entry = RtlInterlockedPopEntrySList( &CachedEventList );
  483. if (Entry != NULL)
  484. {
  485. pCachedEvent = CONTAINING_RECORD( Entry, CACHED_EVENT, ListEntry );
  486. }
  487. else
  488. {
  489. pCachedEvent = ALLOC_MEM( sizeof( CACHED_EVENT ) );
  490. if (pCachedEvent == NULL)
  491. {
  492. return STATUS_NO_MEMORY;
  493. }
  494. status = NtCreateEvent(
  495. &(pCachedEvent->EventHandle), // EventHandle
  496. EVENT_ALL_ACCESS, // DesiredAccess
  497. NULL, // ObjectAttributes
  498. SynchronizationEvent, // EventType
  499. FALSE // InitialState
  500. );
  501. if (!NT_SUCCESS( status ))
  502. {
  503. FREE_MEM( pCachedEvent );
  504. return status;
  505. }
  506. }
  507. *ppCachedEvent = pCachedEvent;
  508. return STATUS_SUCCESS;
  509. }
  510. /***************************************************************************++
  511. Routine Description:
  512. Releases a cached event acquired via HttpApiAcquireCachedEvent().
  513. Arguments:
  514. Event - Supplies the cached event to release
  515. --***************************************************************************/
  516. VOID
  517. HttpApiReleaseCachedEvent(
  518. IN CACHED_EVENT * pCachedEvent
  519. )
  520. {
  521. RtlInterlockedPushEntrySList( &CachedEventList,
  522. &pCachedEvent->ListEntry );
  523. } // HttpApiReleaseCachedEvent