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.

782 lines
23 KiB

  1. /*++
  2. Copyright (c) 1998-2002 Microsoft Corporation
  3. Module Name:
  4. Internal.c
  5. Abstract:
  6. User-mode interface to HTTP.SYS: Internal helper functions.
  7. Author:
  8. Keith Moore (keithmo) 15-Dec-1998
  9. Revision History:
  10. Rajesh Sundaram (rajeshsu) 10-Oct-2000 : Added HTTP client code
  11. --*/
  12. #include "precomp.h"
  13. //
  14. // Private macros.
  15. //
  16. #ifndef MAX
  17. #define MAX(_a, _b) ((_a) > (_b)? (_a): (_b))
  18. #endif
  19. #define MAX_HTTP_DEVICE_NAME \
  20. (MAX(MAX(sizeof(HTTP_SERVER_DEVICE_NAME)/sizeof(WCHAR), sizeof(HTTP_CONTROL_DEVICE_NAME)/sizeof(WCHAR)), \
  21. MAX(sizeof(HTTP_APP_POOL_DEVICE_NAME)/sizeof(WCHAR), sizeof(HTTP_FILTER_DEVICE_NAME)/sizeof(WCHAR))))
  22. //
  23. // Private prototypes.
  24. //
  25. NTSTATUS
  26. HttpApiAcquireCachedEvent(
  27. OUT HANDLE * phEvent
  28. );
  29. //
  30. // Public functions.
  31. //
  32. /***************************************************************************++
  33. Routine Description:
  34. Synchronous wrapper around NtDeviceIoControlFile().
  35. Arguments:
  36. FileHandle - Supplies a handle to the file on which the service is
  37. being performed.
  38. IoControlCode - Subfunction code to determine exactly what operation
  39. is being performed.
  40. pInputBuffer - Optionally supplies an input buffer to be passed to the
  41. device driver. Whether or not the buffer is actually optional is
  42. dependent on the IoControlCode.
  43. InputBufferLength - Length of the pInputBuffer in bytes.
  44. pOutputBuffer - Optionally supplies an output buffer to receive
  45. information from the device driver. Whether or not the buffer is
  46. actually optional is dependent on the IoControlCode.
  47. OutputBufferLength - Length of the pOutputBuffer in bytes.
  48. pBytesTransferred - Optionally receives the number of bytes transferred.
  49. Return Value:
  50. ULONG - Completion status.
  51. --***************************************************************************/
  52. ULONG
  53. HttpApiSynchronousDeviceControl(
  54. IN HANDLE FileHandle,
  55. IN ULONG IoControlCode,
  56. IN PVOID pInputBuffer OPTIONAL,
  57. IN ULONG InputBufferLength,
  58. OUT PVOID pOutputBuffer OPTIONAL,
  59. IN ULONG OutputBufferLength,
  60. OUT PULONG pBytesTransferred OPTIONAL
  61. )
  62. {
  63. NTSTATUS status;
  64. IO_STATUS_BLOCK ioStatusBlock;
  65. LARGE_INTEGER timeout;
  66. HANDLE hEvent;
  67. //
  68. // Try to snag an event object.
  69. //
  70. status = HttpApiAcquireCachedEvent( &hEvent );
  71. if (NT_SUCCESS(status))
  72. {
  73. ASSERT( hEvent != NULL );
  74. //
  75. // Make the call.
  76. //
  77. status = NtDeviceIoControlFile(
  78. FileHandle, // FileHandle
  79. hEvent, // Event
  80. NULL, // ApcRoutine
  81. NULL, // ApcContext
  82. &ioStatusBlock, // IoStatusBlock
  83. IoControlCode, // IoControlCode
  84. pInputBuffer, // InputBuffer
  85. InputBufferLength, // InputBufferLength
  86. pOutputBuffer, // OutputBuffer
  87. OutputBufferLength // OutputBufferLength
  88. );
  89. if (status == STATUS_PENDING)
  90. {
  91. //
  92. // Wait for it to complete.
  93. //
  94. timeout.LowPart = 0xFFFFFFFF;
  95. timeout.HighPart = 0x7FFFFFFF;
  96. status = NtWaitForSingleObject( hEvent,
  97. FALSE,
  98. &timeout );
  99. ASSERT( status == STATUS_SUCCESS );
  100. status = ioStatusBlock.Status;
  101. }
  102. //
  103. // If the call didn't fail and the caller wants the number
  104. // of bytes transferred, grab the value from the I/O status
  105. // block & return it.
  106. //
  107. if (!NT_ERROR(status) && pBytesTransferred != NULL)
  108. {
  109. *pBytesTransferred = (ULONG)ioStatusBlock.Information;
  110. }
  111. //
  112. // Note: We do not have to release the cached event. The event is associated
  113. // with this thread using TLS. There is nothing to cleanup now.
  114. // The event will be cleaned up when the thread goes away.
  115. //
  116. }
  117. return HttpApiNtStatusToWin32Status( status );
  118. } // HttpApiSynchronousDeviceControl
  119. /***************************************************************************++
  120. Routine Description:
  121. Overlapped wrapper around NtDeviceIoControlFile().
  122. Arguments:
  123. FileHandle - Supplies a handle to the file on which the service is
  124. being performed.
  125. pOverlapped - Supplies an OVERLAPPED structure.
  126. IoControlCode - Subfunction code to determine exactly what operation
  127. is being performed.
  128. pInputBuffer - Optionally supplies an input buffer to be passed to the
  129. device driver. Whether or not the buffer is actually optional is
  130. dependent on the IoControlCode.
  131. InputBufferLength - Length of the pInputBuffer in bytes.
  132. pOutputBuffer - Optionally supplies an output buffer to receive
  133. information from the device driver. Whether or not the buffer is
  134. actually optional is dependent on the IoControlCode.
  135. OutputBufferLength - Length of the pOutputBuffer in bytes.
  136. pBytesTransferred - Optionally receives the number of bytes transferred.
  137. Return Value:
  138. ULONG - Completion status.
  139. --***************************************************************************/
  140. ULONG
  141. HttpApiOverlappedDeviceControl(
  142. IN HANDLE FileHandle,
  143. IN OUT LPOVERLAPPED pOverlapped,
  144. IN ULONG IoControlCode,
  145. IN PVOID pInputBuffer OPTIONAL,
  146. IN ULONG InputBufferLength,
  147. OUT PVOID pOutputBuffer OPTIONAL,
  148. IN ULONG OutputBufferLength,
  149. OUT PULONG pBytesTransferred OPTIONAL
  150. )
  151. {
  152. NTSTATUS status;
  153. ULONG result;
  154. //
  155. // Overlapped I/O gets a little more interesting. We'll strive to be
  156. // compatible with NT's KERNEL32 implementation. See DeviceIoControl()
  157. // in \sdnt\base\win32\client\filehops.c for the gory details.
  158. //
  159. ASSERT(pOverlapped);
  160. SET_STATUS_OVERLAPPED_TO_IO_STATUS(pOverlapped, STATUS_PENDING);
  161. status = NtDeviceIoControlFile(
  162. FileHandle, // FileHandle
  163. pOverlapped->hEvent, // Event
  164. NULL, // ApcRoutine
  165. (ULONG_PTR)pOverlapped->hEvent & 1 // ApcContext
  166. ? NULL : pOverlapped,
  167. OVERLAPPED_TO_IO_STATUS(pOverlapped), // IoStatusBlock
  168. IoControlCode, // IoControlCode
  169. pInputBuffer, // InputBuffer
  170. InputBufferLength, // InputBufferLength
  171. pOutputBuffer, // OutputBuffer
  172. OutputBufferLength // OutputBufferLength
  173. );
  174. //
  175. // Set LastError using the original status returned so RtlGetLastNtStatus
  176. // RtlGetLastWin32Error will get the correct status.
  177. //
  178. result = HttpApiNtStatusToWin32Status( status );
  179. //
  180. // Convert all informational and warning status to ERROR_IO_PENDING so
  181. // user can always expect the completion routine gets called.
  182. //
  183. if (NT_INFORMATION(status) || NT_WARNING(status))
  184. {
  185. result = ERROR_IO_PENDING;
  186. }
  187. //
  188. // If the call didn't fail or pend and the caller wants the number of
  189. // bytes transferred, grab the value from the I/O status block &
  190. // return it.
  191. //
  192. if (result == NO_ERROR && pBytesTransferred)
  193. {
  194. //
  195. // We need a __try __except to mimic DeviceIoControl().
  196. //
  197. __try
  198. {
  199. *pBytesTransferred =
  200. (ULONG)OVERLAPPED_TO_IO_STATUS(pOverlapped)->Information;
  201. }
  202. __except( EXCEPTION_EXECUTE_HANDLER )
  203. {
  204. *pBytesTransferred = 0;
  205. }
  206. }
  207. return result;
  208. } // HttpApiOverlappedDeviceControl
  209. /***************************************************************************++
  210. Routine Description:
  211. This routine checks to see if a service has been started. If the service
  212. is in START_PENDING, it waits for it to start completely.
  213. Return Value:
  214. BOOLEAN - TRUE if successful, FALSE otherwise.
  215. --***************************************************************************/
  216. BOOLEAN
  217. QueryAndWaitForServiceStart(
  218. IN SC_HANDLE svcHandle
  219. )
  220. {
  221. SERVICE_STATUS Status;
  222. for(;;)
  223. {
  224. if(!QueryServiceStatus(svcHandle, &Status))
  225. {
  226. return FALSE;
  227. }
  228. switch(Status.dwCurrentState)
  229. {
  230. case SERVICE_RUNNING:
  231. return TRUE;
  232. break;
  233. case SERVICE_START_PENDING:
  234. // Yield to another thread on current processor. If
  235. // no threads are ready to run on the current
  236. // processor, we'll have to sleep to avoid consuming
  237. // too much CPU in what would look almost like a busy
  238. // wait
  239. if(!SwitchToThread())
  240. {
  241. Sleep(50);
  242. }
  243. break;
  244. default:
  245. return FALSE;
  246. break;
  247. }
  248. }
  249. }
  250. /***************************************************************************++
  251. Routine Description:
  252. This routine attempts to start HTTP.SYS.
  253. Return Value:
  254. BOOLEAN - TRUE if successful, FALSE otherwise.
  255. --***************************************************************************/
  256. BOOLEAN
  257. HttpApiTryToStartDriver(
  258. IN PWSTR ServiceName
  259. )
  260. {
  261. BOOLEAN result;
  262. SC_HANDLE scHandle;
  263. SC_HANDLE svcHandle;
  264. result = FALSE; // until proven otherwise...
  265. //
  266. // NOTE:
  267. //
  268. // If an auto-start service calls into HTTP from their Service Entry
  269. // point AND if they have not laid out a dependency on the HTTP service,
  270. // we will deadlock. This is because ServiceStart() will not return until
  271. // all auto-start services are started.
  272. //
  273. // We "could" check for this by checking the status on the named event
  274. // called SC_AUTOSTART_EVENTNAME. If this event is signalled, we have
  275. // completed autostart. However, this event cannot be opened by non-admin
  276. // processes. Therefore, we'll just not even bother checking for this.
  277. //
  278. //
  279. // Open the service controller.
  280. //
  281. scHandle = OpenSCManagerW(
  282. NULL, // lpMachineName
  283. NULL, // lpDatabaseName
  284. SC_MANAGER_CONNECT // dwDesiredAccess
  285. );
  286. if (scHandle != NULL)
  287. {
  288. //
  289. // Try to open the HTTP service.
  290. //
  291. svcHandle = OpenServiceW(
  292. scHandle, // hSCManager
  293. ServiceName, // lpServiceName
  294. SERVICE_START | SERVICE_QUERY_STATUS // dwDesiredAccess
  295. );
  296. if (svcHandle != NULL)
  297. {
  298. //
  299. // First, see if the service is already started. We can't call
  300. // ServiceStart() directly, because of the SCM deadlock mentioned
  301. // above.
  302. //
  303. if(QueryAndWaitForServiceStart(svcHandle))
  304. {
  305. // If the service is already running, we don't have to do
  306. // anything else.
  307. result = TRUE;
  308. }
  309. else
  310. {
  311. //
  312. // Service is not running. So, we try to start it, and wait
  313. // the start to complete.
  314. //
  315. if (StartService( svcHandle, 0, NULL))
  316. {
  317. if(QueryAndWaitForServiceStart(svcHandle))
  318. {
  319. result = TRUE;
  320. }
  321. }
  322. else
  323. {
  324. if(ERROR_SERVICE_ALREADY_RUNNING == GetLastError())
  325. {
  326. // some other thread has already started this service,
  327. // let's treat this as success.
  328. result = TRUE;
  329. }
  330. }
  331. }
  332. CloseServiceHandle( svcHandle );
  333. }
  334. CloseServiceHandle( scHandle );
  335. }
  336. return result;
  337. } // HttpTryToStartDriver
  338. //
  339. // Private functions.
  340. //
  341. /***************************************************************************++
  342. Routine Description:
  343. Helper routine for opening a HTTP.SYS handle.
  344. Arguments:
  345. pHandle - Receives a handle if successful.
  346. DesiredAccess - Supplies the types of access requested to the file.
  347. HandleType - one of Filter, ControlChannel, or AppPool
  348. pObjectName - Optionally supplies the name of the application pool
  349. to create/open.
  350. Options - Supplies zero or more HTTP_OPTION_* flags.
  351. CreateDisposition - Supplies the creation disposition for the new
  352. object.
  353. pSecurityAttributes - Optionally supplies security attributes for
  354. the newly created application pool. Ignored if opening a
  355. control channel.
  356. Return Value:
  357. NTSTATUS - Completion status.
  358. --***************************************************************************/
  359. NTSTATUS
  360. HttpApiOpenDriverHelper(
  361. OUT PHANDLE pHandle,
  362. IN PWCHAR Uri,
  363. IN USHORT UriLength,
  364. IN PWCHAR Proxy,
  365. IN USHORT ProxyLength,
  366. IN PTRANSPORT_ADDRESS pTransportAddress,
  367. IN USHORT TransportAddressLength,
  368. IN ACCESS_MASK DesiredAccess,
  369. IN HTTPAPI_HANDLE_TYPE HandleType,
  370. IN PCWSTR pObjectName OPTIONAL,
  371. IN ULONG Options,
  372. IN ULONG CreateDisposition,
  373. IN PSECURITY_ATTRIBUTES pSecurityAttributes OPTIONAL
  374. )
  375. {
  376. NTSTATUS status;
  377. OBJECT_ATTRIBUTES objectAttributes;
  378. UNICODE_STRING deviceName;
  379. IO_STATUS_BLOCK ioStatusBlock;
  380. ULONG shareAccess;
  381. ULONG createOptions;
  382. PFILE_FULL_EA_INFORMATION pEaBuffer;
  383. WCHAR deviceNameBuffer[MAX_HTTP_DEVICE_NAME + MAX_PATH + 2];
  384. PHTTP_OPEN_PACKET pOpenVersion;
  385. ULONG EaBufferLength;
  386. //
  387. // Validate the parameters.
  388. //
  389. if ((pHandle == NULL) ||
  390. (Options & ~HTTP_OPTION_VALID))
  391. {
  392. return STATUS_INVALID_PARAMETER;
  393. }
  394. if ((HandleType != HttpApiControlChannelHandleType) &&
  395. (HandleType != HttpApiFilterChannelHandleType) &&
  396. (HandleType != HttpApiAppPoolHandleType) &&
  397. (HandleType != HttpApiServerHandleType))
  398. {
  399. return STATUS_INVALID_PARAMETER;
  400. }
  401. //
  402. // Build the open packet.
  403. //
  404. EaBufferLength =
  405. sizeof(HTTP_OPEN_PACKET) +
  406. HTTP_OPEN_PACKET_NAME_LENGTH +
  407. sizeof(FILE_FULL_EA_INFORMATION);
  408. pEaBuffer = RtlAllocateHeap(RtlProcessHeap(),
  409. 0,
  410. EaBufferLength
  411. );
  412. if(!pEaBuffer)
  413. {
  414. return STATUS_INSUFFICIENT_RESOURCES;
  415. }
  416. //
  417. // Build the first EA which will contain the version info.
  418. //
  419. pEaBuffer->Flags = 0;
  420. pEaBuffer->EaNameLength = HTTP_OPEN_PACKET_NAME_LENGTH;
  421. pEaBuffer->EaValueLength = sizeof(*pOpenVersion);
  422. pEaBuffer->NextEntryOffset = 0;
  423. RtlCopyMemory(
  424. pEaBuffer->EaName,
  425. HTTP_OPEN_PACKET_NAME,
  426. HTTP_OPEN_PACKET_NAME_LENGTH + 1);
  427. pOpenVersion = (PHTTP_OPEN_PACKET)
  428. (pEaBuffer->EaName +pEaBuffer->EaNameLength + 1);
  429. pOpenVersion->MajorVersion = HTTP_INTERFACE_VERSION_MAJOR;
  430. pOpenVersion->MinorVersion = HTTP_INTERFACE_VERSION_MINOR;
  431. pOpenVersion->ServerNameLength = UriLength;
  432. pOpenVersion->pServerName = Uri;
  433. pOpenVersion->ProxyNameLength = ProxyLength;
  434. pOpenVersion->pProxyName = Proxy;
  435. pOpenVersion->pTransportAddress = pTransportAddress;
  436. pOpenVersion->TransportAddressLength = TransportAddressLength;
  437. //
  438. // Build the device name.
  439. //
  440. if(HandleType == HttpApiControlChannelHandleType)
  441. {
  442. //
  443. // It's a control channel, so just use the appropriate device name.
  444. //
  445. wcscpy( deviceNameBuffer, HTTP_CONTROL_DEVICE_NAME );
  446. }
  447. else if (HandleType == HttpApiFilterChannelHandleType)
  448. {
  449. //
  450. // It's a fitler channel, so start with the appropriate
  451. // device name.
  452. //
  453. wcscpy( deviceNameBuffer, HTTP_FILTER_DEVICE_NAME );
  454. }
  455. else if(HandleType == HttpApiAppPoolHandleType)
  456. {
  457. //
  458. // It's an app pool, so start with the appropriate device name.
  459. //
  460. wcscpy( deviceNameBuffer, HTTP_APP_POOL_DEVICE_NAME );
  461. //
  462. // Set WRITE_OWNER in DesiredAccess if AppPool is a controller.
  463. //
  464. if ((Options & HTTP_OPTION_CONTROLLER))
  465. {
  466. DesiredAccess |= WRITE_OWNER;
  467. }
  468. }
  469. else
  470. {
  471. ASSERT(HandleType == HttpApiServerHandleType);
  472. wcscpy( deviceNameBuffer, HTTP_SERVER_DEVICE_NAME );
  473. }
  474. if (pObjectName != NULL )
  475. {
  476. //
  477. // It's a named object, so append a slash and the name,
  478. // but first check to ensure we don't overrun our buffer.
  479. //
  480. if ((wcslen(deviceNameBuffer) + wcslen(pObjectName) + 2)
  481. > DIMENSION(deviceNameBuffer))
  482. {
  483. status = STATUS_INVALID_PARAMETER;
  484. goto complete;
  485. }
  486. wcscat( deviceNameBuffer, L"\\" );
  487. wcscat( deviceNameBuffer, pObjectName );
  488. }
  489. //
  490. // Determine the share access and create options based on the
  491. // Flags parameter.
  492. //
  493. shareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
  494. createOptions = 0;
  495. //
  496. // Build the object attributes.
  497. //
  498. status = RtlInitUnicodeStringEx( &deviceName, deviceNameBuffer );
  499. if ( !NT_SUCCESS(status) )
  500. {
  501. goto complete;
  502. }
  503. InitializeObjectAttributes(
  504. &objectAttributes, // ObjectAttributes
  505. &deviceName, // ObjectName
  506. OBJ_CASE_INSENSITIVE, // Attributes
  507. NULL, // RootDirectory
  508. NULL // SecurityDescriptor
  509. );
  510. if (pSecurityAttributes != NULL)
  511. {
  512. objectAttributes.SecurityDescriptor =
  513. pSecurityAttributes->lpSecurityDescriptor;
  514. if (pSecurityAttributes->bInheritHandle)
  515. {
  516. objectAttributes.Attributes |= OBJ_INHERIT;
  517. }
  518. }
  519. //
  520. // Open the UL device.
  521. //
  522. status = NtCreateFile(
  523. pHandle, // FileHandle
  524. DesiredAccess, // DesiredAccess
  525. &objectAttributes, // ObjectAttributes
  526. &ioStatusBlock, // IoStatusBlock
  527. NULL, // AllocationSize
  528. 0, // FileAttributes
  529. shareAccess, // ShareAccess
  530. CreateDisposition, // CreateDisposition
  531. createOptions, // CreateOptions
  532. pEaBuffer, // EaBuffer
  533. EaBufferLength // EaLength
  534. );
  535. complete:
  536. if (!NT_SUCCESS(status))
  537. {
  538. *pHandle = NULL;
  539. }
  540. RtlFreeHeap(RtlProcessHeap(),
  541. 0,
  542. pEaBuffer);
  543. return status;
  544. } // HttpApiOpenDriverHelper
  545. /***************************************************************************++
  546. Routine Description:
  547. Acquires a short-term event from the global event cache. This event
  548. object may only be used for pseudo-synchronous I/O.
  549. We will cache the event and associate it with the thread using TLS.
  550. Therefore acquiring the event simply means checking whether we already
  551. have an associated event with TLS. If not, we'll create an event and
  552. associate it.
  553. Arguments:
  554. phEvent - Receives handle to event
  555. Return Value:
  556. NTSTATUS - Completion status.
  557. --***************************************************************************/
  558. NTSTATUS
  559. HttpApiAcquireCachedEvent(
  560. HANDLE * phEvent
  561. )
  562. {
  563. NTSTATUS status;
  564. HANDLE hEvent = NULL;
  565. //
  566. // See if an event was already associated with TLS
  567. //
  568. hEvent = TlsGetValue( g_TlsIndex );
  569. if (hEvent == NULL)
  570. {
  571. //
  572. // No event associated. Create one now
  573. //
  574. status = NtCreateEvent(
  575. &hEvent, // EventHandle
  576. EVENT_ALL_ACCESS, // DesiredAccess
  577. NULL, // ObjectAttributes
  578. SynchronizationEvent, // EventType
  579. FALSE // InitialState
  580. );
  581. if (!NT_SUCCESS( status ))
  582. {
  583. return status;
  584. }
  585. //
  586. // Associate so subsequent requests on this thread don't have to
  587. // create the event
  588. //
  589. if (!TlsSetValue( g_TlsIndex, hEvent ))
  590. {
  591. //
  592. // If we couldn't set the TLS, then something really bad
  593. // happened. Bail with error
  594. //
  595. NtClose( hEvent );
  596. return STATUS_INSUFFICIENT_RESOURCES;
  597. }
  598. }
  599. *phEvent = hEvent;
  600. return STATUS_SUCCESS;
  601. }