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.

3084 lines
92 KiB

  1. /*++
  2. Copyright (c) 2000-2002 Microsoft Corporation
  3. Module Name:
  4. servinfo.c
  5. Abstract:
  6. Contains the code that implements a server information structure.
  7. Author:
  8. Henry Sanders (henrysa) 10-Aug0-2000
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. //
  13. // Private constants.
  14. //
  15. #define HTTP_PREFIX_W L"HTTP://"
  16. #define HTTP_PREFIX_LENGTH (sizeof(HTTP_PREFIX_W) - sizeof(WCHAR))
  17. #define HTTPS_PREFIX_W L"HTTPS://"
  18. #define HTTPS_PREFIX_LENGTH (sizeof(HTTPS_PREFIX_W) - sizeof(WCHAR))
  19. //
  20. // The macros to compute our hash code.
  21. //
  22. #define HTTP_HASH_CHAR(hash, val) (HASH_MULTIPLY(hash) + (ULONG)(val))
  23. #define HTTP_HASH_ID(hash, val) (HASH_MULTIPLY(hash) + (ULONG)(val))
  24. //
  25. // Which globals have been initialized?
  26. //
  27. #define SERVINFO_CLIENT_LOOKASIDE 0x00000001UL
  28. #define SERVINFO_COMMON_LOOKASIDE 0x00000002UL
  29. #define SERVINFO_LIST 0x00000004UL
  30. #define SERVINFO_LIST_RESOURCE 0x00000008UL
  31. #define SERVINFO_COMMON_TABLE 0x00000010UL
  32. //
  33. // Private globals
  34. //
  35. //
  36. // Which globals have been initialized?
  37. //
  38. ULONG g_ServInfoInitFlags = 0;
  39. //
  40. // Global size of the server info hash table.
  41. //
  42. ULONG g_CommonSIHashTableSize = UC_DEFAULT_SI_TABLE_SIZE;
  43. //
  44. // Server information lookaside
  45. //
  46. NPAGED_LOOKASIDE_LIST g_ClientServerInformationLookaside;
  47. NPAGED_LOOKASIDE_LIST g_CommonServerInformationLookaside;
  48. //
  49. // Server Information list - global list of server information structures.
  50. //
  51. LIST_ENTRY g_ServInfoList;
  52. UL_ERESOURCE g_ServInfoListResource;
  53. //
  54. // Variables used for quick check of URL prefix.
  55. // They must be 64 bit aligned on IA64
  56. //
  57. DECLSPEC_ALIGN(UL_CACHE_LINE)
  58. const USHORT g_HttpPrefix[] = L"http";
  59. DECLSPEC_ALIGN(UL_CACHE_LINE)
  60. const USHORT g_HttpPrefix2[] = L"://\0";
  61. DECLSPEC_ALIGN(UL_CACHE_LINE)
  62. const USHORT g_HttpSPrefix2[] = L"s://";
  63. //
  64. // Pointer to the server info table.
  65. //
  66. PUC_SERVER_INFO_TABLE_HEADER g_UcCommonServerInfoTable;
  67. #ifdef ALLOC_PRAGMA
  68. #pragma alloc_text( INIT, UcInitializeServerInformation )
  69. #pragma alloc_text( PAGE, UcTerminateServerInformation )
  70. #pragma alloc_text( PAGE, UcCreateServerInformation )
  71. #pragma alloc_text( PAGE, UcpLookupCommonServerInformation )
  72. #pragma alloc_text( PAGEUC, UcReferenceServerInformation )
  73. #pragma alloc_text( PAGEUC, UcDereferenceServerInformation )
  74. #pragma alloc_text( PAGEUC, UcSendRequest )
  75. #pragma alloc_text( PAGEUC, UcpFreeServerInformation )
  76. #pragma alloc_text( PAGEUC, UcCloseServerInformation )
  77. #pragma alloc_text( PAGEUC, UcpFreeCommonServerInformation )
  78. #pragma alloc_text( PAGEUC, UcReferenceCommonServerInformation )
  79. #pragma alloc_text( PAGEUC, UcDereferenceCommonServerInformation )
  80. #pragma alloc_text( PAGEUC, UcSetServerContextInformation )
  81. #pragma alloc_text( PAGEUC, UcQueryServerContextInformation )
  82. #pragma alloc_text( PAGEUC, UcpGetConnectionOnServInfo )
  83. #pragma alloc_text( PAGEUC, UcpGetNextConnectionOnServInfo )
  84. #pragma alloc_text( PAGEUC, UcpSetServInfoMaxConnectionCount )
  85. #pragma alloc_text( PAGEUC, UcpFixupIssuerList )
  86. #pragma alloc_text( PAGEUC, UcpNeedToCaptureSerializedCert )
  87. #pragma alloc_text( PAGEUC, UcCaptureSslServerCertInfo )
  88. #endif // ALLOC_PRAGMA
  89. //
  90. // Public functions.
  91. //
  92. /***************************************************************************++
  93. Routine Description:
  94. Initalize the server information code.
  95. Arguments:
  96. Return Value:
  97. NTSTATUS - Completion status.
  98. --***************************************************************************/
  99. NTSTATUS
  100. UcInitializeServerInformation(
  101. VOID
  102. )
  103. {
  104. ULONG i;
  105. ExInitializeNPagedLookasideList(
  106. &g_ClientServerInformationLookaside,
  107. NULL,
  108. NULL,
  109. 0,
  110. sizeof(UC_PROCESS_SERVER_INFORMATION),
  111. UC_PROCESS_SERVER_INFORMATION_POOL_TAG,
  112. 0
  113. );
  114. g_ServInfoInitFlags |= SERVINFO_CLIENT_LOOKASIDE;
  115. UlInitializeResource(
  116. &g_ServInfoListResource,
  117. "Global Server Info Table",
  118. 0,
  119. UC_SERVER_INFO_TABLE_POOL_TAG
  120. );
  121. g_ServInfoInitFlags |= SERVINFO_LIST_RESOURCE;
  122. InitializeListHead(&g_ServInfoList);
  123. g_ServInfoInitFlags |= SERVINFO_LIST;
  124. //
  125. // Each per-process ServerInformation structure points to a globally
  126. // shared per-server structure. Let's initialize this now. Again, no
  127. // quota charging.
  128. //
  129. g_UcCommonServerInfoTable = (PUC_SERVER_INFO_TABLE_HEADER)
  130. UL_ALLOCATE_POOL(
  131. NonPagedPool,
  132. (g_CommonSIHashTableSize *
  133. sizeof(UC_SERVER_INFO_TABLE_HEADER)),
  134. UC_SERVER_INFO_TABLE_POOL_TAG
  135. );
  136. if(NULL == g_UcCommonServerInfoTable)
  137. {
  138. return STATUS_INSUFFICIENT_RESOURCES;
  139. }
  140. g_ServInfoInitFlags |= SERVINFO_COMMON_TABLE;
  141. ExInitializeNPagedLookasideList(
  142. &g_CommonServerInformationLookaside,
  143. NULL,
  144. NULL,
  145. 0,
  146. sizeof(UC_COMMON_SERVER_INFORMATION),
  147. UC_COMMON_SERVER_INFORMATION_POOL_TAG,
  148. 0
  149. );
  150. g_ServInfoInitFlags |= SERVINFO_COMMON_LOOKASIDE;
  151. RtlZeroMemory(g_UcCommonServerInfoTable,
  152. (g_CommonSIHashTableSize *
  153. sizeof(UC_SERVER_INFO_TABLE_HEADER)) );
  154. for (i = 0; i < g_CommonSIHashTableSize; i++)
  155. {
  156. UlInitializeResource(
  157. &g_UcCommonServerInfoTable[i].Resource,
  158. "Common Server Info Table %d",
  159. i,
  160. UC_SERVER_INFO_TABLE_POOL_TAG
  161. );
  162. InitializeListHead(&g_UcCommonServerInfoTable[i].List);
  163. g_UcCommonServerInfoTable[i].Version = 0;
  164. }
  165. return STATUS_SUCCESS;
  166. }
  167. /***************************************************************************++
  168. Routine Description:
  169. Terminate the server information code.
  170. Arguments:
  171. Return Value:
  172. --***************************************************************************/
  173. VOID
  174. UcTerminateServerInformation(
  175. VOID
  176. )
  177. {
  178. ULONG i;
  179. if (g_ServInfoInitFlags & SERVINFO_COMMON_TABLE)
  180. {
  181. ASSERT(g_UcCommonServerInfoTable);
  182. // Make sure this cleanup doesn't happen again.
  183. g_ServInfoInitFlags &= ~SERVINFO_COMMON_TABLE;
  184. for (i = 0; i < g_CommonSIHashTableSize; i++)
  185. {
  186. UlDeleteResource(
  187. &g_UcCommonServerInfoTable[i].Resource
  188. );
  189. ASSERT(IsListEmpty(&g_UcCommonServerInfoTable[i].List));
  190. }
  191. // No Quota
  192. UL_FREE_POOL(g_UcCommonServerInfoTable, UC_SERVER_INFO_TABLE_POOL_TAG);
  193. }
  194. else
  195. {
  196. ASSERT(g_UcCommonServerInfoTable == NULL);
  197. }
  198. if (g_ServInfoInitFlags & SERVINFO_COMMON_LOOKASIDE)
  199. {
  200. // Make sure this cleanup does't happen again.
  201. g_ServInfoInitFlags &= ~SERVINFO_COMMON_LOOKASIDE;
  202. ExDeleteNPagedLookasideList(&g_CommonServerInformationLookaside);
  203. }
  204. if (g_ServInfoInitFlags & SERVINFO_LIST)
  205. {
  206. // Make sure this cleanup does't happen again.
  207. g_ServInfoInitFlags &= ~SERVINFO_LIST;
  208. ASSERT(IsListEmpty(&g_ServInfoList));
  209. }
  210. if (g_ServInfoInitFlags & SERVINFO_LIST_RESOURCE)
  211. {
  212. // Make sure this cleanup doesn't happen again.
  213. g_ServInfoInitFlags &= ~SERVINFO_LIST_RESOURCE;
  214. UlDeleteResource(&g_ServInfoListResource);
  215. }
  216. if (g_ServInfoInitFlags & SERVINFO_CLIENT_LOOKASIDE)
  217. {
  218. // Make sure this cleanup doesn't happen again.
  219. g_ServInfoInitFlags &= ~SERVINFO_CLIENT_LOOKASIDE;
  220. ExDeleteNPagedLookasideList(&g_ClientServerInformationLookaside);
  221. }
  222. }
  223. /***************************************************************************++
  224. Routine Description:
  225. Find a server information structure appropriate for the URI. If no
  226. such structure exists we'll attempt to create one.
  227. As part of this we'll validate that the input URI is well formed.
  228. Arguments:
  229. pServerInfo - Receives a pointer to the server info structure.
  230. pUri - Pointer to the URI string.
  231. uriLength - Length (in bytes) of URI string.
  232. bShared - False if we're to create a new server information
  233. structure, regardless of whether or not one exists.
  234. pProxy - The name of the proxy (optional)
  235. ProxyLength - Length (in bytes) of the proxy name.
  236. Return Value:
  237. Status of attempt.
  238. --***************************************************************************/
  239. NTSTATUS
  240. UcCreateServerInformation(
  241. OUT PUC_PROCESS_SERVER_INFORMATION *pServerInfo,
  242. IN PWSTR pServerName,
  243. IN USHORT ServerNameLength,
  244. IN PWSTR pProxyName,
  245. IN USHORT ProxyNameLength,
  246. IN PTRANSPORT_ADDRESS pTransportAddress,
  247. IN USHORT TransportAddressLength,
  248. IN KPROCESSOR_MODE RequestorMode
  249. )
  250. {
  251. ULONG HashCode;
  252. PUC_PROCESS_SERVER_INFORMATION pInfo;
  253. BOOLEAN bSecure;
  254. LONG i;
  255. PWCHAR pServerNameStart, pServerNameEnd;
  256. PWCHAR pUriEnd;
  257. NTSTATUS Status = STATUS_SUCCESS;
  258. PTA_ADDRESS CurrentAddress;
  259. pInfo = NULL;
  260. bSecure = FALSE;
  261. pServerNameStart = NULL;
  262. __try
  263. {
  264. //
  265. // Probe parameters since they come from user mode.
  266. //
  267. UlProbeWideString(
  268. pServerName,
  269. ServerNameLength,
  270. RequestorMode
  271. );
  272. if(ProxyNameLength)
  273. {
  274. UlProbeWideString(
  275. pProxyName,
  276. ProxyNameLength,
  277. RequestorMode
  278. );
  279. }
  280. UlProbeForRead(
  281. pTransportAddress,
  282. TransportAddressLength,
  283. sizeof(PVOID),
  284. RequestorMode
  285. );
  286. //
  287. // Process the scheme name. We need at least one character after the
  288. // http:// or https://, so the comparision is > instead of >=
  289. //
  290. if(ServerNameLength > HTTP_PREFIX_LENGTH)
  291. {
  292. if (_wcsnicmp(pServerName,
  293. HTTP_PREFIX_W,
  294. HTTP_PREFIX_LENGTH/sizeof(WCHAR)) == 0)
  295. {
  296. pServerNameStart = pServerName +
  297. (HTTP_PREFIX_LENGTH/sizeof(WCHAR));
  298. }
  299. else if(ServerNameLength > HTTPS_PREFIX_LENGTH)
  300. {
  301. if (_wcsnicmp(pServerName,
  302. HTTPS_PREFIX_W,
  303. HTTPS_PREFIX_LENGTH/sizeof(WCHAR)) == 0)
  304. {
  305. pServerNameStart = pServerName +
  306. (HTTPS_PREFIX_LENGTH/sizeof(WCHAR));
  307. bSecure = TRUE;
  308. }
  309. else
  310. {
  311. // neither http:// nor https://
  312. ExRaiseStatus(STATUS_INVALID_PARAMETER);
  313. }
  314. }
  315. else
  316. {
  317. // Not enough space to compare https://
  318. ExRaiseStatus(STATUS_INVALID_PARAMETER);
  319. }
  320. }
  321. else
  322. {
  323. // Not enough space to compare http://
  324. ExRaiseStatus(STATUS_INVALID_PARAMETER);
  325. }
  326. ASSERT(pServerNameStart != NULL);
  327. pUriEnd = pServerName + (ServerNameLength/sizeof(WCHAR));
  328. ASSERT(pServerNameStart != pUriEnd);
  329. pServerNameEnd = pServerNameStart;
  330. HashCode = 0;
  331. while(*pServerNameEnd != L'/')
  332. {
  333. HashCode = HTTP_HASH_CHAR(HashCode, *pServerNameEnd);
  334. pServerNameEnd ++;
  335. if(pServerNameEnd == pUriEnd)
  336. {
  337. break;
  338. }
  339. }
  340. //
  341. // Check for a zero server name
  342. //
  343. if(pServerNameStart == pServerNameEnd)
  344. {
  345. // app passsed http:/// or https:///
  346. ExRaiseStatus(STATUS_INVALID_PARAMETER);
  347. }
  348. // Get a server info from our lookaside cache. If we can't, fail.
  349. pInfo = (PUC_PROCESS_SERVER_INFORMATION)
  350. ExAllocateFromNPagedLookasideList(
  351. &g_ClientServerInformationLookaside
  352. );
  353. if (pInfo == NULL)
  354. {
  355. ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
  356. }
  357. //
  358. // Got an entry, now initialize it.
  359. //
  360. pInfo->RefCount = 0;
  361. pInfo->Signature = UC_PROCESS_SERVER_INFORMATION_SIGNATURE;
  362. for (i = 0; i < DEFAULT_MAX_CONNECTION_COUNT; i++)
  363. {
  364. pInfo->ConnectionArray[i] = NULL;
  365. }
  366. pInfo->Connections = pInfo->ConnectionArray;
  367. pInfo->ActualConnectionCount = DIMENSION(pInfo->ConnectionArray);
  368. pInfo->NextConnection = 0;
  369. pInfo->CurrentConnectionCount = 0;
  370. pInfo->MaxConnectionCount = DIMENSION(pInfo->ConnectionArray);
  371. pInfo->ConnectionTimeout = 0;
  372. UlInitializePushLock(
  373. &pInfo->PushLock,
  374. "Server Information spinlock",
  375. pInfo,
  376. UC_SERVINFO_PUSHLOCK_TAG
  377. );
  378. InitializeListHead(&pInfo->pAuthListHead);
  379. InitializeListHead(&pInfo->Linkage);
  380. pInfo->PreAuthEnable = FALSE;
  381. pInfo->GreatestAuthHeaderMaxLength = 0;
  382. pInfo->ProxyPreAuthEnable = FALSE;
  383. pInfo->pProxyAuthInfo = 0;
  384. pInfo->bSecure = bSecure;
  385. pInfo->bProxy = (BOOLEAN)(ProxyNameLength != 0);
  386. pInfo->IgnoreContinues = TRUE;
  387. pInfo->pTransportAddress = NULL;
  388. pInfo->TransportAddressLength = 0;
  389. //
  390. // Ssl related stuff
  391. //
  392. // Protocol version
  393. pInfo->SslProtocolVersion = 0;
  394. // Server cert stuff
  395. pInfo->ServerCertValidation = HttpSslServerCertValidationAutomatic;
  396. pInfo->ServerCertInfoState = HttpSslServerCertInfoStateNotPresent;
  397. RtlZeroMemory(&pInfo->ServerCertInfo,
  398. sizeof(HTTP_SSL_SERVER_CERT_INFO));
  399. // Client Cert
  400. pInfo->pClientCert = NULL;
  401. //
  402. // Set this to the current process, we will use this field to charge
  403. // allocation quotas for the driver.
  404. //
  405. pInfo->pProcess = IoGetCurrentProcess();
  406. pInfo->pServerInfo = NULL;
  407. pInfo->pNextHopInfo = NULL;
  408. //
  409. // Do a lookup based on the server name
  410. //
  411. Status = UcpLookupCommonServerInformation(
  412. pServerNameStart,
  413. (USHORT)
  414. (pServerNameEnd - pServerNameStart) * sizeof(WCHAR),
  415. HashCode,
  416. pInfo->pProcess,
  417. &pInfo->pServerInfo
  418. );
  419. if(!NT_SUCCESS(Status))
  420. {
  421. ExRaiseStatus(Status);
  422. }
  423. // If a proxy is present, the next hop is the proxy, else it's the
  424. // origin server. Except when we are doing SSL over proxies -- When
  425. // doing SSL, the next hop is always the origin server, because the
  426. // proxy is a tunnel.
  427. // This introduces one wierdness with the CONNECT verb - because the
  428. // CONNECT is sent to the proxy. But, in this case, the version of the
  429. // next hop does not matter. We are using the version to either
  430. // pipeline or do chunked sends & none of these affect the CONNECT
  431. // verb request.
  432. if(ProxyNameLength && !bSecure)
  433. {
  434. PWCHAR pProxyNameStart, pProxyNameEnd;
  435. pProxyNameStart = pProxyName;
  436. pProxyNameEnd = pProxyName + ProxyNameLength/sizeof(WCHAR);
  437. HashCode = 0;
  438. //
  439. // Compute the hash code for the proxy.
  440. //
  441. while(pProxyNameStart != pProxyNameEnd)
  442. {
  443. HashCode = HTTP_HASH_CHAR(HashCode, *pProxyNameStart);
  444. pProxyNameStart ++;
  445. }
  446. Status = UcpLookupCommonServerInformation(
  447. pProxyName,
  448. ProxyNameLength,
  449. HashCode,
  450. pInfo->pProcess,
  451. &pInfo->pNextHopInfo
  452. );
  453. if(!NT_SUCCESS(Status))
  454. {
  455. ExRaiseStatus(Status);
  456. }
  457. }
  458. else
  459. {
  460. // Next hop is the same as the server. We'll just set the pointer
  461. // and take a reference.
  462. //
  463. REFERENCE_COMMON_SERVER_INFORMATION(pInfo->pServerInfo);
  464. pInfo->pNextHopInfo = pInfo->pServerInfo;
  465. }
  466. //
  467. // Make a local copy of Transport Address & point to it.
  468. //
  469. if(TransportAddressLength <= sizeof(pInfo->RemoteAddress))
  470. {
  471. pInfo->pTransportAddress =
  472. &pInfo->RemoteAddress.GenericTransportAddress;
  473. }
  474. else
  475. {
  476. pInfo->pTransportAddress =
  477. UL_ALLOCATE_POOL_WITH_QUOTA(
  478. NonPagedPool,
  479. TransportAddressLength,
  480. UC_TRANSPORT_ADDRESS_POOL_TAG,
  481. pInfo->pProcess
  482. );
  483. if(NULL == pInfo->pTransportAddress)
  484. {
  485. ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
  486. }
  487. }
  488. pInfo->TransportAddressLength = TransportAddressLength;
  489. RtlCopyMemory(pInfo->pTransportAddress,
  490. pTransportAddress,
  491. TransportAddressLength
  492. );
  493. pTransportAddress = pInfo->pTransportAddress;
  494. //
  495. // Fail if we don't have space to read a TRANSPORT_ADDRESS or if there
  496. // are 0 addresses.
  497. //
  498. if((TransportAddressLength <
  499. FIELD_OFFSET(TRANSPORT_ADDRESS, Address)) ||
  500. pTransportAddress->TAAddressCount == 0)
  501. {
  502. ExRaiseStatus(STATUS_INVALID_PARAMETER);
  503. }
  504. CurrentAddress = (PTA_ADDRESS) pTransportAddress->Address;
  505. TransportAddressLength -= FIELD_OFFSET(TRANSPORT_ADDRESS, Address);
  506. for(i=0; i<pTransportAddress->TAAddressCount; i ++)
  507. {
  508. if(TransportAddressLength < FIELD_OFFSET(TA_ADDRESS, Address))
  509. {
  510. ExRaiseStatus(STATUS_ACCESS_VIOLATION);
  511. }
  512. TransportAddressLength =
  513. TransportAddressLength - FIELD_OFFSET(TA_ADDRESS, Address);
  514. if(TransportAddressLength < CurrentAddress->AddressLength)
  515. {
  516. ExRaiseStatus(STATUS_ACCESS_VIOLATION);
  517. }
  518. TransportAddressLength =
  519. TransportAddressLength - CurrentAddress->AddressLength;
  520. switch(CurrentAddress->AddressType)
  521. {
  522. case TDI_ADDRESS_TYPE_IP:
  523. if(CurrentAddress->AddressLength != TDI_ADDRESS_LENGTH_IP)
  524. {
  525. ExRaiseStatus(STATUS_INVALID_PARAMETER);
  526. }
  527. break;
  528. case TDI_ADDRESS_TYPE_IP6:
  529. if(CurrentAddress->AddressLength != TDI_ADDRESS_LENGTH_IP6)
  530. {
  531. ExRaiseStatus(STATUS_INVALID_PARAMETER);
  532. }
  533. break;
  534. default:
  535. ExRaiseStatus(STATUS_INVALID_PARAMETER);
  536. break;
  537. }
  538. CurrentAddress = (PTA_ADDRESS)
  539. (CurrentAddress->Address +
  540. CurrentAddress->AddressLength);
  541. }
  542. if(TransportAddressLength != 0)
  543. {
  544. ExRaiseStatus(STATUS_ACCESS_VIOLATION);
  545. }
  546. //
  547. // Insert the ServInfo in a global list.
  548. //
  549. UlAcquireResourceExclusive(&g_ServInfoListResource, TRUE);
  550. InsertTailList(&g_ServInfoList, &pInfo->Linkage);
  551. //
  552. // Reference the server information structure for our caller.
  553. //
  554. REFERENCE_SERVER_INFORMATION(pInfo);
  555. UlReleaseResource(&g_ServInfoListResource);
  556. UlTrace(SERVINFO,
  557. ("[UcFindServerInformation: Creating PROCESS ServInfo 0x%x "
  558. "for %ws\n", pInfo, pInfo->pServerInfo->pServerName));
  559. *pServerInfo = pInfo;
  560. //
  561. // Page in all of the client code. In Win2K this is API is not very
  562. // efficient. So, if we ever back port to Win2K we'd have to add our
  563. // own ref-counts so that we do it for the first Create only
  564. //
  565. MmLockPagableSectionByHandle(g_ClientImageHandle);
  566. Status = STATUS_SUCCESS;
  567. } __except( UL_EXCEPTION_FILTER())
  568. {
  569. Status = GetExceptionCode();
  570. if(pInfo)
  571. {
  572. UcpFreeServerInformation(pInfo);
  573. }
  574. }
  575. return Status;
  576. }
  577. /***************************************************************************++
  578. Routine Description:
  579. Reference a server information structure.
  580. Arguments:
  581. pServerInfo - Pointer to the server info structure to be referenced.
  582. Return Value:
  583. --***************************************************************************/
  584. __inline
  585. VOID
  586. UcReferenceServerInformation(
  587. PUC_PROCESS_SERVER_INFORMATION pServerInfo
  588. )
  589. {
  590. LONG RefCount;
  591. ASSERT( IS_VALID_SERVER_INFORMATION(pServerInfo) );
  592. RefCount = InterlockedIncrement((PLONG)&pServerInfo->RefCount);
  593. ASSERT( RefCount > 0 );
  594. }
  595. /***************************************************************************++
  596. Routine Description:
  597. Dereference a server information structure. If the reference count goes
  598. to 0, we'll free the structure.
  599. Arguments:
  600. pServerInfo - Pointer to the server info structure to be
  601. dereferenced.
  602. Return Value:
  603. --***************************************************************************/
  604. __inline
  605. VOID
  606. UcDereferenceServerInformation(
  607. PUC_PROCESS_SERVER_INFORMATION pServerInfo
  608. )
  609. {
  610. LONG RefCount;
  611. ASSERT( IS_VALID_SERVER_INFORMATION(pServerInfo) );
  612. RefCount = InterlockedDecrement(&pServerInfo->RefCount);
  613. ASSERT(RefCount >= 0);
  614. if (RefCount == 0)
  615. {
  616. UcpFreeServerInformation(pServerInfo);
  617. }
  618. }
  619. /***************************************************************************++
  620. Routine Description:
  621. Get a particular connection on this server information
  622. If a connection is not already present, it adds a new connection.
  623. Arguments:
  624. pServerInfo - Pointer to the server info structure
  625. ConnectionIndex - Which connection?
  626. ppConnection - Returned pointer to connection
  627. Return Value:
  628. STATUS_SUCCESS
  629. STATUS_INVALID_PARAMETER
  630. --***************************************************************************/
  631. NTSTATUS
  632. UcpGetConnectionOnServInfo(
  633. IN PUC_PROCESS_SERVER_INFORMATION pServInfo,
  634. IN ULONG ConnectionIndex,
  635. OUT PUC_CLIENT_CONNECTION *ppConnection
  636. )
  637. {
  638. NTSTATUS Status;
  639. PUC_CLIENT_CONNECTION pConnection;
  640. BOOLEAN bReuseConnection;
  641. // Sanity check
  642. ASSERT(IS_VALID_SERVER_INFORMATION(pServInfo));
  643. ASSERT(ConnectionIndex != HTTP_REQUEST_ON_CONNECTION_ANY);
  644. // Initialize the locals & output
  645. *ppConnection = NULL;
  646. pConnection = NULL;
  647. bReuseConnection = FALSE;
  648. // Don't disturb please!
  649. UlAcquirePushLockExclusive(&pServInfo->PushLock);
  650. // Is the connection index valid?
  651. if (ConnectionIndex >= pServInfo->MaxConnectionCount)
  652. {
  653. // Nope. Bail out with an error.
  654. Status = STATUS_INVALID_PARAMETER;
  655. goto Release_Quit;
  656. }
  657. // Is there a connection present?
  658. if (pServInfo->Connections[ConnectionIndex] == NULL)
  659. {
  660. // Get a new connection
  661. Status = UcOpenClientConnection(pServInfo, &pConnection);
  662. // Bail out if we couldn't get a new connection
  663. if (!NT_SUCCESS(Status))
  664. {
  665. goto Release_Quit;
  666. }
  667. // OK to add this connection
  668. // Reference the client connection twice, once for the
  669. // server information linkage itself and once for the
  670. // pointer we're returning.
  671. //
  672. // UcOpenClientConnection returns with a ref.
  673. // Save the back pointer to the server information. We don't
  674. // explicitly reference the server information here, that would
  675. // create a circular reference problem. This back pointer is only
  676. // valid while there are requests queued on the connection. See
  677. // the comments about this field in clientconn.h for details.
  678. ADD_CONNECTION_TO_SERV_INFO(pServInfo, pConnection,
  679. ConnectionIndex);
  680. }
  681. *ppConnection = pServInfo->Connections[ConnectionIndex];
  682. REFERENCE_CLIENT_CONNECTION(*ppConnection);
  683. Status = STATUS_SUCCESS;
  684. Release_Quit:
  685. UlReleasePushLock(&pServInfo->PushLock);
  686. return Status;
  687. }
  688. /***************************************************************************++
  689. Routine Description:
  690. Get the next connection on this server information (in round-robin fashion)
  691. Arguments:
  692. pServerInfo - Pointer to the server info structure
  693. ppConnection - Returned pointer to connection
  694. Return Value:
  695. STATUS_SUCCESS
  696. STATUS_INVALID_PARAMETER
  697. --***************************************************************************/
  698. NTSTATUS
  699. UcpGetNextConnectionOnServInfo(
  700. IN PUC_PROCESS_SERVER_INFORMATION pServInfo,
  701. OUT PUC_CLIENT_CONNECTION *ppConnection
  702. )
  703. {
  704. NTSTATUS Status;
  705. PUC_CLIENT_CONNECTION pConnection;
  706. // Sanity check
  707. ASSERT(IS_VALID_SERVER_INFORMATION(pServInfo));
  708. // Initialize the locals & output
  709. *ppConnection = NULL;
  710. pConnection = NULL;
  711. UlAcquirePushLockExclusive(&pServInfo->PushLock);
  712. // See if we can add a new connection
  713. if (pServInfo->CurrentConnectionCount < pServInfo->MaxConnectionCount)
  714. {
  715. ULONG i, j;
  716. // Get a new connection
  717. Status = UcOpenClientConnection(pServInfo, &pConnection);
  718. // Bail out if we couldn't get a new connection
  719. if (!NT_SUCCESS(Status))
  720. {
  721. goto Quit;
  722. }
  723. // Update output
  724. *ppConnection = pConnection;
  725. REFERENCE_CLIENT_CONNECTION(pConnection);
  726. // Put this connection in the connections array
  727. // Start seaching form the NextConnection as it is most likely
  728. // empty.
  729. ASSERT(pServInfo->NextConnection < pServInfo->MaxConnectionCount);
  730. i = pServInfo->NextConnection;
  731. j = pServInfo->MaxConnectionCount;
  732. while(j)
  733. {
  734. if (pServInfo->Connections[i] == NULL)
  735. {
  736. ADD_CONNECTION_TO_SERV_INFO(pServInfo, pConnection, i);
  737. pConnection = NULL;
  738. break;
  739. }
  740. i = (i + 1) % pServInfo->MaxConnectionCount;
  741. j--;
  742. }
  743. // Update NextConnection
  744. pServInfo->NextConnection = (i+1) % pServInfo->MaxConnectionCount;
  745. ASSERT(pConnection == NULL);
  746. }
  747. else
  748. {
  749. ASSERT(pServInfo->NextConnection < pServInfo->MaxConnectionCount);
  750. *ppConnection = pServInfo->Connections[pServInfo->NextConnection];
  751. pServInfo->NextConnection = (pServInfo->NextConnection + 1) %
  752. pServInfo->MaxConnectionCount;
  753. REFERENCE_CLIENT_CONNECTION(*ppConnection);
  754. Status = STATUS_SUCCESS;
  755. }
  756. Quit:
  757. UlReleasePushLock(&pServInfo->PushLock);
  758. return Status;
  759. }
  760. /***************************************************************************++
  761. Routine Description:
  762. Send a request to a remote server. We take a server information
  763. structure and a request, then we find a connection for that request and
  764. assign the request to it. We then start the request processing going.
  765. Arguments:
  766. pServerInfo - Pointer to the server info structure
  767. pRequest - Pointer to the request to be sent.
  768. Return Value:
  769. NTSTATUS - Status of attempt to send request.
  770. --***************************************************************************/
  771. NTSTATUS
  772. UcSendRequest(
  773. PUC_PROCESS_SERVER_INFORMATION pServerInfo,
  774. PUC_HTTP_REQUEST pRequest
  775. )
  776. {
  777. KIRQL OldIRQL;
  778. PUC_CLIENT_CONNECTION pConnection;
  779. NTSTATUS Status;
  780. ASSERT( IS_VALID_SERVER_INFORMATION(pServerInfo) );
  781. if (pRequest->ConnectionIndex == HTTP_REQUEST_ON_CONNECTION_ANY)
  782. {
  783. Status = UcpGetNextConnectionOnServInfo(pServerInfo, &pConnection);
  784. }
  785. else
  786. {
  787. Status = UcpGetConnectionOnServInfo(pServerInfo,
  788. pRequest->ConnectionIndex,
  789. &pConnection);
  790. }
  791. if (!NT_SUCCESS(Status))
  792. {
  793. return Status;
  794. }
  795. //
  796. // At this point we have a valid client connection. Send the request on it.
  797. // Get the spin lock, queue the request, and check the state of the
  798. // connection.
  799. //
  800. pRequest->RequestIRP->Tail.Overlay.DriverContext[0] = NULL;
  801. pRequest->pConnection = pConnection;
  802. // Reference the connection for this request. This reference will be removed
  803. // when the request is off all of our lists, either due to a cancel or a
  804. // completion.
  805. REFERENCE_CLIENT_CONNECTION(pConnection);
  806. UlAcquireSpinLock(&pConnection->SpinLock, &OldIRQL);
  807. InsertTailList(&pConnection->PendingRequestList, &pRequest->Linkage);
  808. if(pRequest->RequestFlags.CompleteIrpEarly)
  809. {
  810. UC_WRITE_TRACE_LOG(
  811. g_pUcTraceLog,
  812. UC_ACTION_REQUEST_COMPLETE_EARLY,
  813. pConnection,
  814. pRequest,
  815. pRequest->RequestIRP,
  816. 0
  817. );
  818. ASSERT(pRequest->RequestFlags.RequestBuffered);
  819. //
  820. // NULL the request IRP so that it does not get completed
  821. // twice.
  822. //
  823. pRequest->RequestIRP = 0;
  824. UlReleaseSpinLock(&pConnection->SpinLock, OldIRQL);
  825. DEREFERENCE_CLIENT_CONNECTION(pConnection);
  826. return STATUS_SUCCESS;
  827. }
  828. else if(pRequest->RequestFlags.RequestBuffered)
  829. {
  830. BOOLEAN RequestCancelled;
  831. //
  832. // We can't send now, so leave it queued. Since we're leaving this
  833. // request queued set it up for cancelling now.
  834. //
  835. IoMarkIrpPending(pRequest->RequestIRP);
  836. RequestCancelled = UcSetRequestCancelRoutine(
  837. pRequest,
  838. UcpCancelPendingRequest
  839. );
  840. if (RequestCancelled)
  841. {
  842. UC_WRITE_TRACE_LOG(
  843. g_pUcTraceLog,
  844. UC_ACTION_REQUEST_CANCELLED,
  845. pConnection,
  846. pRequest,
  847. pRequest->RequestIRP,
  848. UlongToPtr((ULONG)STATUS_CANCELLED)
  849. );
  850. pRequest->RequestIRP = NULL;
  851. //
  852. // Make sure that any new API calls for this request ID are failed.
  853. //
  854. UcSetFlag(&pRequest->RequestFlags.Value,
  855. UcMakeRequestCancelledFlag());
  856. }
  857. UC_WRITE_TRACE_LOG(
  858. g_pUcTraceLog,
  859. UC_ACTION_REQUEST_QUEUED,
  860. pConnection,
  861. pRequest,
  862. pRequest->RequestIRP,
  863. UlongToPtr((ULONG)STATUS_PENDING)
  864. );
  865. Status = STATUS_PENDING;
  866. UlReleaseSpinLock(&pConnection->SpinLock, OldIRQL);
  867. }
  868. else
  869. {
  870. Status = UcSendRequestOnConnection(pConnection, pRequest, OldIRQL);
  871. }
  872. DEREFERENCE_CLIENT_CONNECTION(pConnection);
  873. return Status;
  874. }
  875. /***************************************************************************++
  876. Routine Description:
  877. Free a server information structure. The server information structure
  878. must be at zero references.
  879. Arguments:
  880. pInfo - Pointer to the server information structure to be freed.
  881. Return Value:
  882. --***************************************************************************/
  883. VOID
  884. UcpFreeServerInformation(
  885. PUC_PROCESS_SERVER_INFORMATION pInfo
  886. )
  887. {
  888. PUC_CLIENT_CONNECTION pConn;
  889. KIRQL OldIrql;
  890. KEVENT ConnectionCleanupEvent;
  891. ULONG i;
  892. ASSERT( IS_VALID_SERVER_INFORMATION(pInfo) );
  893. PAGED_CODE();
  894. UlAcquireResourceExclusive(&g_ServInfoListResource, TRUE);
  895. RemoveEntryList(&pInfo->Linkage);
  896. UlReleaseResource(&g_ServInfoListResource);
  897. ASSERT(pInfo->RefCount == 0);
  898. KeInitializeEvent(&ConnectionCleanupEvent, SynchronizationEvent, FALSE);
  899. // Now walk through the connections on this structure and dereference
  900. // them.
  901. for (i = 0; i < pInfo->MaxConnectionCount; i++)
  902. {
  903. if ((pConn = pInfo->Connections[i]) == NULL)
  904. continue;
  905. ASSERT( UC_IS_VALID_CLIENT_CONNECTION(pConn) );
  906. UlAcquireSpinLock(&pConn->SpinLock, &OldIrql);
  907. ASSERT(pConn->pEvent == NULL);
  908. pConn->pEvent = &ConnectionCleanupEvent;
  909. UC_WRITE_TRACE_LOG(
  910. g_pUcTraceLog,
  911. UC_ACTION_SERVINFO_FREE,
  912. pConn,
  913. UlongToPtr(pConn->ConnectionState),
  914. UlongToPtr(pConn->ConnectionStatus),
  915. UlongToPtr(pConn->Flags)
  916. );
  917. switch(pConn->ConnectionState)
  918. {
  919. case UcConnectStateConnectCleanup:
  920. case UcConnectStateConnectCleanupBegin:
  921. // Cleanup has already begun, don't do it again.
  922. UlReleaseSpinLock(&pConn->SpinLock, OldIrql);
  923. break;
  924. case UcConnectStateConnectIdle:
  925. // Initiate a cleanup.
  926. pConn->ConnectionState = UcConnectStateConnectCleanup;
  927. pConn->ConnectionStatus = STATUS_CANCELLED;
  928. UcKickOffConnectionStateMachine(
  929. pConn,
  930. OldIrql,
  931. UcConnectionPassive
  932. );
  933. break;
  934. case UcConnectStateConnectPending:
  935. // If its in UcConnectStateConnectPending, then we will clean
  936. // up when the connect completes.
  937. UlReleaseSpinLock(&pConn->SpinLock, OldIrql);
  938. break;
  939. default:
  940. UlReleaseSpinLock(&pConn->SpinLock, OldIrql);
  941. UC_CLOSE_CONNECTION(pConn, TRUE, STATUS_CANCELLED);
  942. break;
  943. }
  944. DEREFERENCE_CLIENT_CONNECTION(pConn);
  945. //
  946. // Wait for the ref on this client connection to go to 0
  947. //
  948. KeWaitForSingleObject(
  949. &ConnectionCleanupEvent,
  950. Executive,
  951. KernelMode,
  952. FALSE,
  953. NULL
  954. );
  955. UlTrace(SERVINFO,
  956. ("[UcpFreeServerInformation]: Done with Connection 0x%x \n",
  957. pConn));
  958. }
  959. // Free Connections array if necessary
  960. if (pInfo->Connections != pInfo->ConnectionArray)
  961. {
  962. UL_FREE_POOL_WITH_QUOTA(pInfo->Connections,
  963. UC_PROCESS_SERVER_CONNECTION_POOL_TAG,
  964. NonPagedPool,
  965. pInfo->ActualConnectionCount *
  966. sizeof(PUC_CLIENT_CONNECTION),
  967. pInfo->pProcess);
  968. pInfo->Connections = NULL;
  969. }
  970. if(pInfo->pTransportAddress &&
  971. (pInfo->pTransportAddress !=
  972. &pInfo->RemoteAddress.GenericTransportAddress))
  973. {
  974. UL_FREE_POOL_WITH_QUOTA(
  975. pInfo->pTransportAddress,
  976. UC_TRANSPORT_ADDRESS_POOL_TAG,
  977. NonPagedPool,
  978. pInfo->TransportAddressLength,
  979. pInfo->pProcess
  980. );
  981. }
  982. //
  983. // Flush the pre-auth cache for this servinfo.
  984. //
  985. UcDeleteAllURIEntries(pInfo);
  986. if(pInfo->pProxyAuthInfo != NULL)
  987. {
  988. UcDestroyInternalAuth(pInfo->pProxyAuthInfo,
  989. pInfo->pProcess);
  990. pInfo->pProxyAuthInfo = 0;
  991. }
  992. UC_FREE_SERIALIZED_CERT(&pInfo->ServerCertInfo, pInfo->pProcess);
  993. UC_FREE_CERT_ISSUER_LIST(&pInfo->ServerCertInfo, pInfo->pProcess);
  994. UlTrace(SERVINFO,
  995. ("[UcpFreeServerInformation]: Freeing PROCESS Servinfo 0x%x "
  996. " for URI %ws \n", pInfo, pInfo->pServerInfo->pServerName));
  997. if(pInfo->pServerInfo)
  998. {
  999. DEREFERENCE_COMMON_SERVER_INFORMATION(pInfo->pServerInfo);
  1000. }
  1001. if(pInfo->pNextHopInfo)
  1002. {
  1003. DEREFERENCE_COMMON_SERVER_INFORMATION(pInfo->pNextHopInfo);
  1004. }
  1005. //
  1006. // Terminate the push lock
  1007. //
  1008. UlDeletePushLock(&pInfo->PushLock);
  1009. ExFreeToNPagedLookasideList(&g_ClientServerInformationLookaside, pInfo);
  1010. }
  1011. /***************************************************************************++
  1012. Routine Description:
  1013. A utility routine to close the servinfo structure. This is called from
  1014. the CLOSE IRP (i.e when a process is dying)
  1015. Arguments:
  1016. pServInfo - Pointer to the server information
  1017. Return Value:
  1018. --***************************************************************************/
  1019. VOID
  1020. UcCloseServerInformation(
  1021. IN PUC_PROCESS_SERVER_INFORMATION pServInfo
  1022. )
  1023. {
  1024. DEREFERENCE_SERVER_INFORMATION(pServInfo);
  1025. MmUnlockPagableImageSection(g_ClientImageHandle);
  1026. }
  1027. /***************************************************************************++
  1028. Routine Description:
  1029. Lookup a server information structure in the server info table. If we
  1030. don't find one return NULL.
  1031. Arguments:
  1032. pServerName - Pointer to unicode server name
  1033. HashCode - Hashcode for the server name. May need to be trimmed
  1034. as appropriate for the table size.
  1035. ServerNameLength - Length (in chars) of server name string.
  1036. ProcessID - ID of the process we're trying to find.
  1037. pVersion - Receives the Version valus of the header entry.
  1038. Return Value:
  1039. A pointer to a server info if we find one, or NULL if not.
  1040. --***************************************************************************/
  1041. NTSTATUS
  1042. UcpLookupCommonServerInformation(
  1043. IN PWSTR pServerName,
  1044. IN USHORT ServerNameLength,
  1045. IN ULONG CommonHashCode,
  1046. IN PEPROCESS pProcess,
  1047. OUT PUC_COMMON_SERVER_INFORMATION *pCommonInfo
  1048. )
  1049. {
  1050. PUC_COMMON_SERVER_INFORMATION pInfo = NULL;
  1051. PUC_SERVER_INFO_TABLE_HEADER pHeader;
  1052. PLIST_ENTRY pListHead, pCurrent;
  1053. LONG i;
  1054. BOOLEAN bAllocated = FALSE;
  1055. NTSTATUS Status = STATUS_SUCCESS;
  1056. *pCommonInfo = NULL;
  1057. // Trim the HashCode.
  1058. CommonHashCode %= g_CommonSIHashTableSize;
  1059. pHeader = &g_UcCommonServerInfoTable[CommonHashCode];
  1060. //
  1061. // The common server information will not be created that often, so it's
  1062. // OK for this to be an exclusive lock. We will change it later if required
  1063. //
  1064. // If we change this to use a shared lock during the search, then we have
  1065. // to do the same "Version" trick that we do with the per-process server
  1066. // information - After we acquire the exclusive lock we need to check if
  1067. // another thread has come an inserted the same entry
  1068. //
  1069. UlAcquireResourceExclusive(&pHeader->Resource, TRUE);
  1070. pListHead = &pHeader->List;
  1071. pCurrent = pListHead->Flink;
  1072. //
  1073. // Since we are going to touch user mode pointers, we better be in
  1074. // _try _except
  1075. //
  1076. __try
  1077. {
  1078. // Walk through the list of server information structures on this list.
  1079. // For each structure, make sure that the name of the server is the same
  1080. // length as the input server name, and if it is compare the two names.
  1081. //
  1082. while (pCurrent != pListHead)
  1083. {
  1084. // Retrieve the server information from the list entry.
  1085. pInfo = CONTAINING_RECORD(
  1086. pCurrent,
  1087. UC_COMMON_SERVER_INFORMATION,
  1088. Linkage
  1089. );
  1090. ASSERT( IS_VALID_COMMON_SERVER_INFORMATION(pInfo) );
  1091. // See if they're the same length
  1092. if (pInfo->pProcess == pProcess &&
  1093. pInfo->ServerNameLength == ServerNameLength)
  1094. {
  1095. if(_wcsnicmp(pInfo->pServerName,
  1096. pServerName,
  1097. ServerNameLength/sizeof(WCHAR)) == 0)
  1098. {
  1099. break;
  1100. }
  1101. }
  1102. pCurrent = pInfo->Linkage.Flink;
  1103. }
  1104. if (pCurrent != pListHead)
  1105. {
  1106. //
  1107. // Take a ref for the caller.
  1108. //
  1109. ASSERT(NULL != pInfo);
  1110. UlTrace(SERVINFO,
  1111. ("[UcpLookupCommonServerInformation]: Found COMMON servinfo"
  1112. " 0x%x for %ws (HTTP Version %d) \n",
  1113. pInfo, pInfo->pServerName, pInfo->Version11));
  1114. REFERENCE_COMMON_SERVER_INFORMATION(pInfo);
  1115. }
  1116. else
  1117. {
  1118. //
  1119. // Let's create a new one.
  1120. //
  1121. bAllocated = TRUE;
  1122. pInfo = (PUC_COMMON_SERVER_INFORMATION)
  1123. ExAllocateFromNPagedLookasideList(
  1124. &g_CommonServerInformationLookaside
  1125. );
  1126. if (pInfo == NULL)
  1127. {
  1128. ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
  1129. }
  1130. // Got an entry, now initialize it.
  1131. //
  1132. pInfo->RefCount = 1;
  1133. pInfo->Signature = UC_COMMON_SERVER_INFORMATION_SIGNATURE;
  1134. pInfo->Version11 = 0;
  1135. pInfo->pHeader = pHeader;
  1136. pInfo->ServerNameLength = ServerNameLength;
  1137. pInfo->AnsiServerNameLength = ServerNameLength/sizeof(WCHAR);
  1138. pInfo->bPortNumber = 0;
  1139. pInfo->pProcess = pProcess;
  1140. //
  1141. // Go ahead and insert it, if there is a failure from now onwards,
  1142. // we'll call Deref.
  1143. //
  1144. InsertTailList(&pHeader->List, &pInfo->Linkage);
  1145. if ((ServerNameLength+sizeof(WCHAR)) <= SERVER_NAME_BUFFER_SIZE)
  1146. {
  1147. pInfo->pServerName = pInfo->ServerNameBuffer;
  1148. pInfo->pAnsiServerName = pInfo->AnsiServerNameBuffer;
  1149. }
  1150. else
  1151. {
  1152. pInfo->pServerName = NULL;
  1153. pInfo->pAnsiServerName = NULL;
  1154. // The server name is too big, need to allocate a buffer.
  1155. pInfo->pServerName =
  1156. (PWSTR) UL_ALLOCATE_POOL_WITH_QUOTA(
  1157. NonPagedPool,
  1158. (ServerNameLength+sizeof(WCHAR)),
  1159. SERVER_NAME_BUFFER_POOL_TAG,
  1160. pProcess
  1161. );
  1162. if (pInfo->pServerName == NULL)
  1163. {
  1164. ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
  1165. }
  1166. pInfo->pAnsiServerName =
  1167. (PSTR) UL_ALLOCATE_POOL_WITH_QUOTA(
  1168. NonPagedPool,
  1169. pInfo->AnsiServerNameLength + 1,
  1170. SERVER_NAME_BUFFER_POOL_TAG,
  1171. pProcess
  1172. );
  1173. if(pInfo->pAnsiServerName == NULL)
  1174. {
  1175. ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
  1176. }
  1177. }
  1178. RtlCopyMemory(pInfo->pServerName,
  1179. pServerName,
  1180. ServerNameLength
  1181. );
  1182. pInfo->pServerName[ServerNameLength/sizeof(WCHAR)] = L'\0';
  1183. //
  1184. // Convert the name to ANSI, we need this for generating the host
  1185. // header.
  1186. //
  1187. HttpUnicodeToUTF8Encode(
  1188. pInfo->pServerName,
  1189. pInfo->ServerNameLength/sizeof(WCHAR),
  1190. (PUCHAR)pInfo->pAnsiServerName,
  1191. pInfo->AnsiServerNameLength,
  1192. NULL,
  1193. TRUE
  1194. );
  1195. pInfo->pAnsiServerName[pInfo->AnsiServerNameLength] = '\0';
  1196. //
  1197. // Determine if there is a port number present in the server name
  1198. // To optimize, start from the end of the server name
  1199. // Any char except digit [0-9] and ':' means no port
  1200. // a ':' means a port number if followed by digits
  1201. //
  1202. for (i = (LONG)pInfo->AnsiServerNameLength - 1; i >= 0; i--)
  1203. {
  1204. if (pInfo->pAnsiServerName[i] == ':' &&
  1205. i != (LONG)pInfo->AnsiServerNameLength - 1)
  1206. {
  1207. // Yes, there is a port number
  1208. pInfo->bPortNumber = 1;
  1209. break;
  1210. }
  1211. if (!isdigit(pInfo->pAnsiServerName[i]))
  1212. {
  1213. // Non-digit chars means no port number
  1214. break;
  1215. }
  1216. }
  1217. UlTrace(
  1218. SERVINFO,
  1219. ("[UcpLookupCommonServerInformation]: Created COMMON servinfo"
  1220. " 0x%x for %ws \n", pInfo, pInfo->pServerName)
  1221. );
  1222. }
  1223. } __except( UL_EXCEPTION_FILTER())
  1224. {
  1225. Status = GetExceptionCode();
  1226. if(bAllocated && pInfo)
  1227. {
  1228. DEREFERENCE_COMMON_SERVER_INFORMATION(pInfo);
  1229. }
  1230. pInfo = NULL;
  1231. }
  1232. UlReleaseResource(&pHeader->Resource);
  1233. *pCommonInfo = pInfo;
  1234. return Status;
  1235. }
  1236. /***************************************************************************++
  1237. Routine Description:
  1238. Free a server information structure. The server information structure
  1239. must be at zero references.
  1240. Arguments:
  1241. pInfo - Pointer to the server information structure to be
  1242. freed.
  1243. Return Value:
  1244. --***************************************************************************/
  1245. VOID
  1246. UcpFreeCommonServerInformation(
  1247. PUC_COMMON_SERVER_INFORMATION pInfo
  1248. )
  1249. {
  1250. ASSERT( IS_VALID_COMMON_SERVER_INFORMATION(pInfo) );
  1251. ASSERT(pInfo->RefCount == 0);
  1252. UlTrace(SERVINFO,
  1253. ("[UcpFreeServerInformation]: Freeing COMMON Servinfo 0x%x "
  1254. " for URI %ws \n", pInfo, pInfo->pServerName));
  1255. // If we've got a server name buffer allocated, free it first if
  1256. // it's not NULL.
  1257. if (pInfo->pServerName != pInfo->ServerNameBuffer)
  1258. {
  1259. if (pInfo->pServerName != NULL)
  1260. {
  1261. UL_FREE_POOL_WITH_QUOTA(
  1262. pInfo->pServerName,
  1263. SERVER_NAME_BUFFER_POOL_TAG,
  1264. NonPagedPool,
  1265. pInfo->ServerNameLength + sizeof(WCHAR),
  1266. pInfo->pProcess
  1267. );
  1268. }
  1269. }
  1270. if (pInfo->pAnsiServerName != pInfo->AnsiServerNameBuffer)
  1271. {
  1272. if (pInfo->pAnsiServerName != NULL)
  1273. {
  1274. UL_FREE_POOL_WITH_QUOTA(
  1275. pInfo->pAnsiServerName,
  1276. SERVER_NAME_BUFFER_POOL_TAG,
  1277. NonPagedPool,
  1278. pInfo->AnsiServerNameLength + 1,
  1279. pInfo->pProcess
  1280. );
  1281. }
  1282. }
  1283. UlAcquireResourceExclusive(&pInfo->pHeader->Resource, TRUE);
  1284. RemoveEntryList(&pInfo->Linkage);
  1285. UlReleaseResource(&pInfo->pHeader->Resource);
  1286. ExFreeToNPagedLookasideList(&g_CommonServerInformationLookaside, pInfo);
  1287. }
  1288. /***************************************************************************++
  1289. Routine Description:
  1290. Reference a server information structure.
  1291. Arguments:
  1292. pServerInfo - Pointer to the server info structure to be referenced.
  1293. Return Value:
  1294. --***************************************************************************/
  1295. __inline
  1296. VOID
  1297. UcReferenceCommonServerInformation(
  1298. PUC_COMMON_SERVER_INFORMATION pServerInfo
  1299. )
  1300. {
  1301. LONG RefCount;
  1302. ASSERT( IS_VALID_COMMON_SERVER_INFORMATION(pServerInfo) );
  1303. RefCount = InterlockedIncrement(&pServerInfo->RefCount);
  1304. ASSERT( RefCount > 0 );
  1305. }
  1306. /***************************************************************************++
  1307. Routine Description:
  1308. Dereference a server information structure. If the reference count goes
  1309. to 0, we'll free the structure.
  1310. Arguments:
  1311. pServerInfo - Pointer to the server info structure to be
  1312. dereferenced.
  1313. Return Value:
  1314. --***************************************************************************/
  1315. __inline
  1316. VOID
  1317. UcDereferenceCommonServerInformation(
  1318. PUC_COMMON_SERVER_INFORMATION pServerInfo
  1319. )
  1320. {
  1321. LONG RefCount;
  1322. ASSERT( IS_VALID_COMMON_SERVER_INFORMATION(pServerInfo) );
  1323. RefCount = InterlockedDecrement(&pServerInfo->RefCount);
  1324. ASSERT(RefCount >= 0);
  1325. if (RefCount == 0)
  1326. {
  1327. UcpFreeCommonServerInformation(pServerInfo);
  1328. }
  1329. }
  1330. /***************************************************************************++
  1331. Routine Description:
  1332. Arguments:
  1333. Return Value:
  1334. Status
  1335. --***************************************************************************/
  1336. NTSTATUS
  1337. UcpSetServInfoMaxConnectionCount(
  1338. IN PUC_PROCESS_SERVER_INFORMATION pServInfo,
  1339. IN ULONG NewCount
  1340. )
  1341. {
  1342. UC_CLIENT_CONNECTION **ppConnection, **ppOldConnection;
  1343. ULONG i, ActualCount, OldActualCount;
  1344. NTSTATUS Status;
  1345. UlAcquirePushLockExclusive(&pServInfo->PushLock);
  1346. // Reducing connection count?
  1347. if (NewCount < pServInfo->MaxConnectionCount)
  1348. {
  1349. Status = STATUS_SUCCESS;
  1350. if (pServInfo->CurrentConnectionCount > NewCount)
  1351. {
  1352. // We can't reduce connection below current connection count!
  1353. Status = STATUS_INVALID_PARAMETER;
  1354. }
  1355. else
  1356. {
  1357. // See if we can reduce connections from higher indices.
  1358. for (i = NewCount; i < pServInfo->MaxConnectionCount; i++)
  1359. if (pServInfo->Connections[i] != NULL)
  1360. Status = STATUS_INVALID_PARAMETER;
  1361. }
  1362. if (Status == STATUS_SUCCESS)
  1363. {
  1364. InterlockedExchange((LONG *)&pServInfo->MaxConnectionCount,
  1365. (LONG)NewCount);
  1366. if (pServInfo->NextConnection >= pServInfo->MaxConnectionCount)
  1367. {
  1368. pServInfo->NextConnection = 0;
  1369. }
  1370. }
  1371. }
  1372. else if (NewCount == pServInfo->MaxConnectionCount)
  1373. {
  1374. // Trivial case!
  1375. Status = STATUS_SUCCESS;
  1376. }
  1377. else if (NewCount <= pServInfo->ActualConnectionCount)
  1378. {
  1379. // We already have space for the additional connections, just use it!
  1380. #if DBG
  1381. for (i = pServInfo->MaxConnectionCount;
  1382. i < pServInfo->ActualConnectionCount;
  1383. i++)
  1384. {
  1385. ASSERT(pServInfo->Connections[i] == NULL);
  1386. }
  1387. #endif
  1388. InterlockedExchange((LONG *)&pServInfo->MaxConnectionCount,
  1389. (LONG)NewCount);
  1390. Status = STATUS_SUCCESS;
  1391. }
  1392. else
  1393. {
  1394. ASSERT(NewCount > pServInfo->MaxConnectionCount);
  1395. ASSERT(NewCount > pServInfo->ActualConnectionCount);
  1396. ActualCount = NewCount;
  1397. // allocate new Connection Array
  1398. //
  1399. // NOTE: sizeof(PUC_CLIENT_CONNECTION) is intentional because we are
  1400. // allocating space for storing pointers & not the structure itself.
  1401. //
  1402. ppConnection = (UC_CLIENT_CONNECTION **)UL_ALLOCATE_POOL_WITH_QUOTA(
  1403. NonPagedPool,
  1404. ActualCount * sizeof(PUC_CLIENT_CONNECTION),
  1405. UC_PROCESS_SERVER_CONNECTION_POOL_TAG,
  1406. pServInfo->pProcess);
  1407. if (ppConnection == NULL)
  1408. {
  1409. Status = STATUS_INSUFFICIENT_RESOURCES;
  1410. goto Release_Quit;
  1411. }
  1412. // Copy the pointers
  1413. for (i = 0; i < pServInfo->MaxConnectionCount; i++)
  1414. {
  1415. ppConnection[i] = pServInfo->Connections[i];
  1416. }
  1417. for (; i < ActualCount; i++)
  1418. {
  1419. ppConnection[i] = NULL;
  1420. }
  1421. // set new connection array
  1422. ppOldConnection = pServInfo->Connections;
  1423. pServInfo->Connections = ppConnection;
  1424. // Set new max connection count
  1425. InterlockedExchange((LONG *)&pServInfo->MaxConnectionCount,
  1426. (LONG)NewCount);
  1427. // Set new actual connection count
  1428. OldActualCount = pServInfo->ActualConnectionCount;
  1429. pServInfo->ActualConnectionCount = ActualCount;
  1430. // release spinlock
  1431. UlReleasePushLock(&pServInfo->PushLock);
  1432. // free memory if necessary
  1433. if (ppOldConnection != pServInfo->ConnectionArray)
  1434. {
  1435. UL_FREE_POOL_WITH_QUOTA(
  1436. ppOldConnection,
  1437. UC_PROCESS_SERVER_CONNECTION_POOL_TAG,
  1438. NonPagedPool,
  1439. OldActualCount * sizeof(PUC_CLIENT_CONNECTION),
  1440. pServInfo->pProcess
  1441. );
  1442. }
  1443. Status = STATUS_SUCCESS;
  1444. goto Quit;
  1445. }
  1446. Release_Quit:
  1447. UlReleasePushLock(&pServInfo->PushLock);
  1448. Quit:
  1449. return Status;
  1450. }
  1451. /***************************************************************************++
  1452. Routine Description:
  1453. This routine is called to set server config. We will be calling this
  1454. from the HttpSetServerConfig IOCTL.
  1455. NOTE: This is a IN_DIRECT IOCTL.
  1456. Arguments:
  1457. pServerInfo - Pointer to the server info structure
  1458. pConfigID - The config object that is being set.
  1459. pMdlBuffer - InputBuffer
  1460. BufferLength - Length of Input Buffer
  1461. Return Value:
  1462. Status
  1463. --***************************************************************************/
  1464. NTSTATUS
  1465. UcSetServerContextInformation(
  1466. IN PUC_PROCESS_SERVER_INFORMATION pServInfo,
  1467. IN HTTP_SERVER_CONFIG_ID ConfigID,
  1468. IN PVOID pInBuffer,
  1469. IN ULONG InBufferLength,
  1470. IN PIRP pIrp
  1471. )
  1472. {
  1473. NTSTATUS Status = STATUS_SUCCESS;
  1474. LONG Value;
  1475. PAGED_CODE();
  1476. __try
  1477. {
  1478. // If the app has passed input buffers, make sure that it's
  1479. // readable.
  1480. if(!InBufferLength)
  1481. {
  1482. UlProbeForRead(pInBuffer,
  1483. InBufferLength,
  1484. sizeof(ULONG),
  1485. pIrp->RequestorMode
  1486. );
  1487. }
  1488. switch(ConfigID)
  1489. {
  1490. case HttpServerConfigConnectionTimeout:
  1491. {
  1492. if(InBufferLength != sizeof(ULONG))
  1493. {
  1494. return(STATUS_INVALID_PARAMETER);
  1495. }
  1496. pServInfo->ConnectionTimeout = (*(ULONG *)pInBuffer);
  1497. break;
  1498. }
  1499. case HttpServerConfigIgnoreContinueState:
  1500. {
  1501. ULONG bValue;
  1502. if(InBufferLength != sizeof(ULONG))
  1503. {
  1504. return STATUS_INVALID_PARAMETER;
  1505. }
  1506. bValue = (*(ULONG *)pInBuffer);
  1507. if(bValue == 0 || bValue == 1)
  1508. {
  1509. pServInfo->IgnoreContinues = bValue;
  1510. }
  1511. else
  1512. {
  1513. Status = STATUS_INVALID_PARAMETER;
  1514. }
  1515. break;
  1516. }
  1517. case HttpServerConfigConnectionCount:
  1518. {
  1519. if(InBufferLength != sizeof(ULONG))
  1520. {
  1521. return STATUS_INVALID_PARAMETER;
  1522. }
  1523. Value = (*(LONG *)pInBuffer);
  1524. if(Value <= 0)
  1525. {
  1526. Status = STATUS_INVALID_PARAMETER;
  1527. }
  1528. else
  1529. {
  1530. Status = UcpSetServInfoMaxConnectionCount(pServInfo,
  1531. (ULONG)Value);
  1532. }
  1533. break;
  1534. }
  1535. case HttpServerConfigPreAuthState:
  1536. {
  1537. if(InBufferLength != sizeof(ULONG))
  1538. {
  1539. return STATUS_INVALID_PARAMETER;
  1540. }
  1541. Value = (*(LONG *)pInBuffer);
  1542. if(Value == 0 || Value == 1)
  1543. {
  1544. pServInfo->PreAuthEnable = Value;
  1545. }
  1546. else
  1547. {
  1548. Status = STATUS_INVALID_PARAMETER;
  1549. }
  1550. break;
  1551. }
  1552. case HttpServerConfigProxyPreAuthState:
  1553. {
  1554. if(InBufferLength != sizeof(ULONG))
  1555. {
  1556. return STATUS_INVALID_PARAMETER;
  1557. }
  1558. Value = (*(LONG *)pInBuffer);
  1559. if(Value == 0 || Value == 1)
  1560. {
  1561. pServInfo->ProxyPreAuthEnable = Value;
  1562. }
  1563. else
  1564. {
  1565. Status = STATUS_INVALID_PARAMETER;
  1566. }
  1567. break;
  1568. }
  1569. case HttpServerConfigProxyPreAuthFlushCache:
  1570. {
  1571. PUC_HTTP_AUTH pAuth;
  1572. if(InBufferLength != 0)
  1573. {
  1574. return STATUS_INVALID_PARAMETER;
  1575. }
  1576. UlTrace(AUTH_CACHE,
  1577. ("[UcSetServerContextInformation]: Flushing Proxy Auth "
  1578. "cache for %ws\n",
  1579. pServInfo->pServerInfo->pServerName));
  1580. UlAcquirePushLockExclusive(&pServInfo->PushLock);
  1581. pAuth = pServInfo->pProxyAuthInfo;
  1582. pServInfo->pProxyAuthInfo = NULL;
  1583. UlReleasePushLock(&pServInfo->PushLock);
  1584. if(pAuth)
  1585. {
  1586. UcDestroyInternalAuth(pAuth, pServInfo->pProcess);
  1587. }
  1588. break;
  1589. }
  1590. case HttpServerConfigPreAuthFlushURICache:
  1591. {
  1592. if(InBufferLength != 0)
  1593. {
  1594. return STATUS_INVALID_PARAMETER;
  1595. }
  1596. UlTrace(AUTH_CACHE,
  1597. ("[UcSetServerContextInformation]: Flushing Auth cache"
  1598. " for %ws \n", pServInfo->pServerInfo->pServerName));
  1599. UcDeleteAllURIEntries(pServInfo);
  1600. break;
  1601. }
  1602. case HttpServerConfigServerCertValidation:
  1603. {
  1604. ULONG Option;
  1605. if(InBufferLength != sizeof(ULONG))
  1606. {
  1607. return STATUS_INVALID_PARAMETER;
  1608. }
  1609. Option = *(ULONG *)pInBuffer;
  1610. if (Option != HttpSslServerCertValidationIgnore &&
  1611. Option != HttpSslServerCertValidationManual &&
  1612. Option != HttpSslServerCertValidationManualOnce &&
  1613. Option != HttpSslServerCertValidationAutomatic)
  1614. {
  1615. return STATUS_INVALID_PARAMETER;
  1616. }
  1617. InterlockedExchange((PLONG)&pServInfo->ServerCertValidation,
  1618. Option);
  1619. break;
  1620. }
  1621. case HttpServerConfigServerCertAccept:
  1622. {
  1623. ULONG i;
  1624. PUC_CLIENT_CONNECTION pConnection;
  1625. PUC_CLIENT_CONNECTION pCloseConn = NULL;
  1626. ULONG Action;
  1627. KIRQL NewIrql;
  1628. // Input must be an ULONG.
  1629. if (InBufferLength != sizeof(ULONG))
  1630. {
  1631. return STATUS_INVALID_PARAMETER;
  1632. }
  1633. // Must be TRUE or FALSE
  1634. Action = *(ULONG *)pInBuffer;
  1635. if (Action != TRUE && Action != FALSE)
  1636. {
  1637. return STATUS_INVALID_PARAMETER;
  1638. }
  1639. UlAcquirePushLockExclusive(&pServInfo->PushLock);
  1640. if (pServInfo->ServerCertInfoState ==
  1641. HttpSslServerCertInfoStateNotValidated)
  1642. {
  1643. //
  1644. // Server certificate was not validated.
  1645. //
  1646. Status = STATUS_SUCCESS;
  1647. if (Action == TRUE)
  1648. {
  1649. // The server cert was accepted.
  1650. pServInfo->ServerCertInfoState =
  1651. HttpSslServerCertInfoStateValidated;
  1652. }
  1653. else
  1654. {
  1655. // The server cert was rejected.
  1656. pServInfo->ServerCertInfoState =
  1657. HttpSslServerCertInfoStateNotPresent;
  1658. }
  1659. // For each connection...
  1660. for (i = 0; i < pServInfo->MaxConnectionCount; i++)
  1661. {
  1662. if ((pConnection = pServInfo->Connections[i]) == NULL)
  1663. continue;
  1664. ASSERT(UC_IS_VALID_CLIENT_CONNECTION(pConnection));
  1665. UlAcquireSpinLock(&pConnection->SpinLock, &NewIrql);
  1666. if (pConnection->ConnectionState ==
  1667. UcConnectStatePerformingSslHandshake)
  1668. {
  1669. if (pConnection->SslState ==
  1670. UcSslStateValidatingServerCert)
  1671. {
  1672. // The connection was waiting for server cert
  1673. // validation.
  1674. if (Action == TRUE)
  1675. {
  1676. // Cert was accepted. Proceed.
  1677. pConnection->SslState =
  1678. UcSslStateHandshakeComplete;
  1679. pConnection->ConnectionState =
  1680. UcConnectStateConnectReady;
  1681. UcKickOffConnectionStateMachine(
  1682. pConnection,
  1683. NewIrql,
  1684. UcConnectionWorkItem
  1685. );
  1686. }
  1687. else
  1688. {
  1689. ASSERT(NULL == pCloseConn);
  1690. // Cert was rejected. Close the connection.
  1691. pCloseConn = pConnection;
  1692. UlReleaseSpinLock(&pConnection->SpinLock,
  1693. NewIrql);
  1694. }
  1695. }
  1696. else if (pConnection->SslState ==
  1697. UcSslStateServerCertReceived)
  1698. {
  1699. // Waiting for server cert comparision.
  1700. UcKickOffConnectionStateMachine(
  1701. pConnection,
  1702. NewIrql,
  1703. UcConnectionWorkItem
  1704. );
  1705. }
  1706. else
  1707. {
  1708. UlReleaseSpinLock(&pConnection->SpinLock,
  1709. NewIrql);
  1710. }
  1711. }
  1712. else
  1713. {
  1714. UlReleaseSpinLock(&pConnection->SpinLock,
  1715. NewIrql);
  1716. }
  1717. }
  1718. }
  1719. UlReleasePushLock(&pServInfo->PushLock);
  1720. if (pCloseConn)
  1721. {
  1722. UC_CLOSE_CONNECTION(pCloseConn, TRUE, STATUS_CANCELLED);
  1723. }
  1724. break;
  1725. }
  1726. case HttpServerConfigSslProtocolVersion:
  1727. {
  1728. if(InBufferLength != sizeof(ULONG))
  1729. {
  1730. return STATUS_INVALID_PARAMETER;
  1731. }
  1732. else
  1733. {
  1734. ULONG SslProtocolVersion = *(PULONG)pInBuffer;
  1735. InterlockedExchange((LONG *)&pServInfo->SslProtocolVersion,
  1736. (LONG)SslProtocolVersion);
  1737. Status = STATUS_SUCCESS;
  1738. }
  1739. break;
  1740. }
  1741. case HttpServerConfigClientCert:
  1742. {
  1743. if(InBufferLength != sizeof(PVOID))
  1744. {
  1745. return STATUS_INVALID_PARAMETER;
  1746. }
  1747. else
  1748. {
  1749. PVOID pClientCert;
  1750. // Make sure pInBuffer is PVOID aligned.
  1751. UlProbeForRead(pInBuffer,
  1752. InBufferLength,
  1753. sizeof(PVOID),
  1754. pIrp->RequestorMode);
  1755. pClientCert = *(PVOID *)pInBuffer;
  1756. InterlockedExchangePointer(&pServInfo->pClientCert,
  1757. pClientCert);
  1758. Status = STATUS_SUCCESS;
  1759. }
  1760. break;
  1761. }
  1762. default:
  1763. Status = STATUS_INVALID_PARAMETER;
  1764. break;
  1765. }
  1766. } __except( UL_EXCEPTION_FILTER())
  1767. {
  1768. Status = GetExceptionCode();
  1769. }
  1770. return Status;
  1771. }
  1772. /***************************************************************************++
  1773. Routine Description:
  1774. This routine is called to query server config.
  1775. NOTE: This is a OUT_DIRECT IOCTL.
  1776. Arguments:
  1777. pServerInfo - Pointer to the server info structure
  1778. pConfigID - The config object that is being set.
  1779. pMdlBuffer - OutputBuffer
  1780. BufferLength - Length of Output Buffer
  1781. pBytesTaken - Amount we have written
  1782. Return Value:
  1783. Status
  1784. --***************************************************************************/
  1785. NTSTATUS
  1786. UcQueryServerContextInformation(
  1787. IN PUC_PROCESS_SERVER_INFORMATION pServInfo,
  1788. IN HTTP_SERVER_CONFIG_ID ConfigID,
  1789. IN PVOID pOutBuffer,
  1790. IN ULONG OutBufferLength,
  1791. OUT PULONG pBytesTaken,
  1792. IN PVOID pAppBase
  1793. )
  1794. {
  1795. NTSTATUS Status = STATUS_SUCCESS;
  1796. *pBytesTaken = 0;
  1797. ASSERT(NULL != pOutBuffer);
  1798. ASSERT(pOutBuffer == ALIGN_UP_POINTER(pOutBuffer, ULONG));
  1799. //
  1800. // NOTE: Since this is an OUT_DIRECT ioctl, we don't need to be in a
  1801. // _try _except block.
  1802. //
  1803. switch(ConfigID)
  1804. {
  1805. case HttpServerConfigConnectionTimeout:
  1806. {
  1807. PULONG Value = (PULONG)pOutBuffer;
  1808. *pBytesTaken = sizeof(pServInfo->ConnectionTimeout);
  1809. if(OutBufferLength < sizeof(pServInfo->ConnectionTimeout))
  1810. {
  1811. return STATUS_BUFFER_TOO_SMALL;
  1812. }
  1813. *Value = pServInfo->ConnectionTimeout;
  1814. break;
  1815. }
  1816. case HttpServerConfigIgnoreContinueState:
  1817. {
  1818. PULONG Value = (PULONG)pOutBuffer;
  1819. *pBytesTaken = sizeof(pServInfo->IgnoreContinues);
  1820. if(OutBufferLength < sizeof(pServInfo->IgnoreContinues))
  1821. {
  1822. return STATUS_BUFFER_TOO_SMALL;
  1823. }
  1824. *Value = pServInfo->IgnoreContinues;
  1825. break;
  1826. }
  1827. case HttpServerConfigConnectionCount:
  1828. {
  1829. PLONG Value = (PLONG)pOutBuffer;
  1830. *pBytesTaken = sizeof(pServInfo->MaxConnectionCount);
  1831. if(OutBufferLength < sizeof(pServInfo->MaxConnectionCount))
  1832. {
  1833. return STATUS_BUFFER_TOO_SMALL;
  1834. }
  1835. *Value = pServInfo->MaxConnectionCount;
  1836. break;
  1837. }
  1838. case HttpServerConfigPreAuthState:
  1839. {
  1840. PLONG Value = (PLONG)pOutBuffer;
  1841. *pBytesTaken = sizeof(pServInfo->PreAuthEnable);
  1842. if(OutBufferLength < sizeof(pServInfo->PreAuthEnable))
  1843. {
  1844. return STATUS_BUFFER_TOO_SMALL;
  1845. }
  1846. *Value = pServInfo->PreAuthEnable;
  1847. break;
  1848. }
  1849. case HttpServerConfigProxyPreAuthState:
  1850. {
  1851. PLONG Value = (PLONG)pOutBuffer;
  1852. *pBytesTaken = sizeof(pServInfo->ProxyPreAuthEnable);
  1853. if(OutBufferLength < sizeof(pServInfo->ProxyPreAuthEnable))
  1854. {
  1855. return STATUS_BUFFER_TOO_SMALL;
  1856. }
  1857. *Value = pServInfo->ProxyPreAuthEnable;
  1858. break;
  1859. }
  1860. case HttpServerConfigServerCert:
  1861. {
  1862. PHTTP_SSL_SERVER_CERT_INFO pCertInfo = NULL;
  1863. PHTTP_SSL_SERVER_CERT_INFO pOutCertInfo = NULL;
  1864. PUCHAR ptr = NULL;
  1865. // Make sure pOutBuffer is PVOID aligned.
  1866. if (pOutBuffer != ALIGN_UP_POINTER(pOutBuffer, PVOID))
  1867. {
  1868. return STATUS_DATATYPE_MISALIGNMENT_ERROR;
  1869. }
  1870. // by default, server cert is not present
  1871. Status = STATUS_NOT_FOUND;
  1872. UlAcquirePushLockExclusive(&pServInfo->PushLock);
  1873. //
  1874. // Server certificate there?
  1875. //
  1876. if(pServInfo->ServerCertInfoState !=
  1877. HttpSslServerCertInfoStateNotPresent)
  1878. {
  1879. pCertInfo = &pServInfo->ServerCertInfo;
  1880. *pBytesTaken = sizeof(HTTP_SSL_SERVER_CERT_INFO) +
  1881. pCertInfo->Cert.SerializedCertLength +
  1882. pCertInfo->Cert.SerializedCertStoreLength;
  1883. //
  1884. // Can the output buffer hold the certificate?
  1885. //
  1886. if (OutBufferLength < *pBytesTaken)
  1887. {
  1888. // Nope
  1889. Status = STATUS_BUFFER_TOO_SMALL;
  1890. }
  1891. else
  1892. {
  1893. //
  1894. // Yeap...copy the certificate info
  1895. //
  1896. pOutCertInfo = (PHTTP_SSL_SERVER_CERT_INFO)pOutBuffer;
  1897. // First, copy SERVER_CERT_INFO structure
  1898. RtlCopyMemory(pOutCertInfo,
  1899. pCertInfo,
  1900. sizeof(HTTP_SSL_SERVER_CERT_INFO));
  1901. // Make space for serialized cert
  1902. ptr = (PUCHAR)(pOutCertInfo + 1);
  1903. pOutCertInfo->Cert.pSerializedCert = ptr;
  1904. // Copy serialized cert
  1905. RtlCopyMemory(ptr,
  1906. pCertInfo->Cert.pSerializedCert,
  1907. pCertInfo->Cert.SerializedCertLength);
  1908. // Make space for serialized cert store
  1909. ptr = ptr + pCertInfo->Cert.SerializedCertLength;
  1910. pOutCertInfo->Cert.pSerializedCertStore = ptr;
  1911. // Copy serialized cert store
  1912. RtlCopyMemory(ptr,
  1913. pCertInfo->Cert.pSerializedCertStore,
  1914. pCertInfo->Cert.SerializedCertStoreLength);
  1915. // Fix app's serialized cert pointer
  1916. pOutCertInfo->Cert.pSerializedCert = (PUCHAR)pAppBase +
  1917. (pOutCertInfo->Cert.pSerializedCert -
  1918. (PUCHAR)pOutCertInfo);
  1919. // Fix app's serialized cert store pointer
  1920. pOutCertInfo->Cert.pSerializedCertStore =(PUCHAR)pAppBase +
  1921. (pOutCertInfo->Cert.pSerializedCertStore -
  1922. (PUCHAR)pOutCertInfo);
  1923. Status = STATUS_SUCCESS;
  1924. }
  1925. }
  1926. UlReleasePushLock(&pServInfo->PushLock);
  1927. break;
  1928. }
  1929. case HttpServerConfigServerCertValidation:
  1930. {
  1931. *pBytesTaken = sizeof(ULONG);
  1932. if(OutBufferLength < sizeof(ULONG))
  1933. {
  1934. Status = STATUS_BUFFER_TOO_SMALL;
  1935. }
  1936. else
  1937. {
  1938. // No locks needed!
  1939. *(PULONG)pOutBuffer = pServInfo->ServerCertValidation;
  1940. Status = STATUS_SUCCESS;
  1941. }
  1942. break;
  1943. }
  1944. case HttpServerConfigSslProtocolVersion:
  1945. {
  1946. *pBytesTaken = sizeof(ULONG);
  1947. if(OutBufferLength < sizeof(ULONG))
  1948. {
  1949. Status = STATUS_BUFFER_TOO_SMALL;
  1950. }
  1951. else
  1952. {
  1953. // No locks needed!
  1954. *(PULONG)pOutBuffer = pServInfo->SslProtocolVersion;
  1955. Status = STATUS_SUCCESS;
  1956. }
  1957. break;
  1958. }
  1959. case HttpServerConfigClientCert:
  1960. {
  1961. // Make sure pOutBuffer is PVOID aligned.
  1962. if (pOutBuffer != ALIGN_UP_POINTER(pOutBuffer, PVOID))
  1963. {
  1964. return STATUS_DATATYPE_MISALIGNMENT_ERROR;
  1965. }
  1966. *pBytesTaken = sizeof(PVOID);
  1967. if(OutBufferLength < sizeof(PVOID))
  1968. {
  1969. Status = STATUS_BUFFER_TOO_SMALL;
  1970. }
  1971. else
  1972. {
  1973. // No locks needed!
  1974. *(PVOID *)pOutBuffer = pServInfo->pClientCert;
  1975. Status = STATUS_SUCCESS;
  1976. }
  1977. break;
  1978. }
  1979. case HttpServerConfigClientCertIssuerList:
  1980. {
  1981. PHTTP_SSL_CERT_ISSUER_INFO pIssuerInfo;
  1982. PUCHAR ptr;
  1983. // Make sure pOutBuffer is PVOID aligned.
  1984. if (pOutBuffer != ALIGN_UP_POINTER(pOutBuffer, PVOID))
  1985. {
  1986. return STATUS_DATATYPE_MISALIGNMENT_ERROR;
  1987. }
  1988. // By default, no issuer list is present.
  1989. Status = STATUS_NOT_FOUND;
  1990. UlAcquirePushLockExclusive(&pServInfo->PushLock);
  1991. if (pServInfo->ServerCertInfo.IssuerInfo.IssuerListLength)
  1992. {
  1993. // Compute the bytes required for storing issuer list
  1994. *pBytesTaken = sizeof(HTTP_SSL_CERT_ISSUER_INFO) +
  1995. pServInfo->ServerCertInfo.IssuerInfo.IssuerListLength;
  1996. // By default, output buffer is small.
  1997. Status = STATUS_BUFFER_TOO_SMALL;
  1998. if (OutBufferLength >= *pBytesTaken)
  1999. {
  2000. //
  2001. // Output buffer is big enough to hold issuer list.
  2002. //
  2003. pIssuerInfo = (PHTTP_SSL_CERT_ISSUER_INFO)pOutBuffer;
  2004. // First copy CERT_ISSUER_INFO structure
  2005. RtlCopyMemory(pIssuerInfo,
  2006. &pServInfo->ServerCertInfo.IssuerInfo,
  2007. sizeof(HTTP_SSL_CERT_ISSUER_INFO));
  2008. // Make space for Issuer List
  2009. ptr = (PUCHAR)(pIssuerInfo + 1);
  2010. pIssuerInfo->pIssuerList = (PUCHAR)pAppBase +
  2011. (ptr - (PUCHAR)pOutBuffer);
  2012. // Copy the actual Issuer List
  2013. RtlCopyMemory(
  2014. ptr,
  2015. pServInfo->ServerCertInfo.IssuerInfo.pIssuerList,
  2016. pServInfo->ServerCertInfo.IssuerInfo.IssuerListLength);
  2017. // Fixup app's pointers.
  2018. Status = UcpFixupIssuerList(
  2019. ptr,
  2020. pServInfo->ServerCertInfo.IssuerInfo.pIssuerList,
  2021. pServInfo->ServerCertInfo.IssuerInfo.IssuerCount,
  2022. pServInfo->ServerCertInfo.IssuerInfo.IssuerListLength);
  2023. ASSERT(Status == STATUS_SUCCESS);
  2024. }
  2025. }
  2026. UlReleasePushLock(&pServInfo->PushLock);
  2027. break;
  2028. }
  2029. default:
  2030. Status = STATUS_INVALID_PARAMETER;
  2031. break;
  2032. }
  2033. return Status;
  2034. }
  2035. /****************************************************************************++
  2036. Routine Description:
  2037. Determines whether to make an kernel mode copy of serialized certificate
  2038. passed by the filter. In general, we avoid copying as much as possible.
  2039. Arguments:
  2040. pCertInfo - Kernel copy of Filter supplied server certificate info
  2041. pServInfo - ServInfo that will eventually receive this pCertInfo
  2042. Return Value:
  2043. TRUE - copy serialized certificate (Too bad!)
  2044. FALSE - Don't copy the serialized certificate :-)
  2045. --****************************************************************************/
  2046. BOOLEAN
  2047. UcpNeedToCaptureSerializedCert(
  2048. IN PHTTP_SSL_SERVER_CERT_INFO pCertInfo,
  2049. IN PUC_PROCESS_SERVER_INFORMATION pServInfo
  2050. )
  2051. {
  2052. BOOLEAN retval;
  2053. // Sanity check
  2054. ASSERT(pCertInfo);
  2055. ASSERT(IS_VALID_SERVER_INFORMATION(pServInfo));
  2056. // By default, copy serialized certificate
  2057. retval = TRUE;
  2058. UlAcquirePushLockExclusive(&pServInfo->PushLock);
  2059. switch(pServInfo->ServerCertValidation)
  2060. {
  2061. case HttpSslServerCertValidationIgnore:
  2062. case HttpSslServerCertValidationAutomatic:
  2063. //
  2064. // In ignore or automatic mode, only one copy of the server
  2065. // certificate is needed (in case the user wants to see it).
  2066. // If one is already present, don't copy. NotValidated, Validated
  2067. // states indicate presence of server certificate.
  2068. //
  2069. if (pServInfo->ServerCertInfoState ==
  2070. HttpSslServerCertInfoStateNotValidated ||
  2071. pServInfo->ServerCertInfoState ==
  2072. HttpSslServerCertInfoStateValidated)
  2073. {
  2074. retval = FALSE;
  2075. }
  2076. break;
  2077. case HttpSslServerCertValidationManualOnce:
  2078. //
  2079. // If ManualOnce case, if the new cert is same as old one,
  2080. // skip copying. Compare to see if they are same.
  2081. //
  2082. if (pServInfo->ServerCertInfoState ==
  2083. HttpSslServerCertInfoStateValidated &&
  2084. UC_COMPARE_CERT_HASH(&pServInfo->ServerCertInfo, pCertInfo))
  2085. {
  2086. retval = FALSE;
  2087. }
  2088. break;
  2089. case HttpSslServerCertValidationManual:
  2090. // Always copy.
  2091. break;
  2092. default:
  2093. ASSERT(FALSE);
  2094. break;
  2095. }
  2096. UlReleasePushLock(&pServInfo->PushLock);
  2097. return TRUE;
  2098. }
  2099. /****************************************************************************++
  2100. Routine Description:
  2101. Fixes the pointers present in the Issuer List returned by Schannel.
  2102. Arguments:
  2103. IN OUT PUCHAR pIssuerList - Kernel mode copy of Issuer List
  2104. IN PUCHAR BaseAddr - User mode pointer to Issuer List
  2105. IN ULONG IssuerCount - Number of Issuers
  2106. IN ULONG IssuerListLength - Total length of memory blob
  2107. Return Value:
  2108. NTSTATUS
  2109. --****************************************************************************/
  2110. NTSTATUS
  2111. UcpFixupIssuerList(
  2112. IN OUT PUCHAR pIssuerList,
  2113. IN PUCHAR BaseAddr,
  2114. IN ULONG IssuerCount,
  2115. IN ULONG IssuerListLength
  2116. )
  2117. {
  2118. NTSTATUS Status;
  2119. ULONG i;
  2120. PHTTP_DATA_BLOB pDataBlob;
  2121. ASSERT(pIssuerList && IssuerCount && IssuerListLength);
  2122. ASSERT(BaseAddr);
  2123. Status = STATUS_INVALID_PARAMETER;
  2124. pDataBlob = (PHTTP_DATA_BLOB)pIssuerList;
  2125. // Blob must at least contain 'IssuerCount' number of HTTP_DATA_BLOB
  2126. if (IssuerListLength <= sizeof(PHTTP_DATA_BLOB) * IssuerCount)
  2127. {
  2128. goto error;
  2129. }
  2130. // For each HTTP_DATA_BLOB, adjust pbData.
  2131. for (i = 0; i < IssuerCount; i++)
  2132. {
  2133. pDataBlob[i].pbData = pIssuerList + (pDataBlob[i].pbData - BaseAddr);
  2134. // pbData must point somewhere inside the blob.
  2135. if (pDataBlob[i].pbData >= pIssuerList + IssuerListLength)
  2136. {
  2137. goto error;
  2138. }
  2139. }
  2140. Status = STATUS_SUCCESS;
  2141. error:
  2142. return Status;
  2143. }
  2144. /***************************************************************************++
  2145. Routine Description:
  2146. Captures SSL server certificate passed down in a UlFilterAppWrite
  2147. call with a UlFilterBufferSslServerCert type.
  2148. Arguments:
  2149. pCertInfo - the cert data to capture
  2150. SslCertInfoLength - size of the buffer passed to us
  2151. ppCapturedCert - this is where we stick the info we get
  2152. pTakenLength - gets the number of bytes we read
  2153. --***************************************************************************/
  2154. NTSTATUS
  2155. UcCaptureSslServerCertInfo(
  2156. IN PUX_FILTER_CONNECTION pConnection,
  2157. IN PHTTP_SSL_SERVER_CERT_INFO pCertInfo,
  2158. IN ULONG CertInfoLength,
  2159. OUT PHTTP_SSL_SERVER_CERT_INFO pCopyCertInfo,
  2160. OUT PULONG pTakenLength
  2161. )
  2162. {
  2163. NTSTATUS Status;
  2164. PUC_CLIENT_CONNECTION pClientConn;
  2165. PUCHAR pCert;
  2166. PUCHAR pCertStore;
  2167. PUCHAR pIssuerList;
  2168. // Sanity check
  2169. ASSERT(IS_VALID_FILTER_CONNECTION(pConnection));
  2170. ASSERT(pCertInfo && CertInfoLength);
  2171. ASSERT(pCopyCertInfo);
  2172. ASSERT(pTakenLength);
  2173. // Initialize locals
  2174. Status = STATUS_SUCCESS;
  2175. pClientConn = (PUC_CLIENT_CONNECTION)pConnection->pConnectionContext;
  2176. ASSERT(UC_IS_VALID_CLIENT_CONNECTION(pClientConn));
  2177. pCert = NULL;
  2178. pCertStore = NULL;
  2179. pIssuerList = NULL;
  2180. // Initialize output variables
  2181. *pTakenLength = 0;
  2182. //
  2183. // See if it's ok to capture...
  2184. //
  2185. if (CertInfoLength != sizeof(HTTP_SSL_SERVER_CERT_INFO))
  2186. {
  2187. return STATUS_INVALID_PARAMETER;
  2188. }
  2189. //
  2190. // Capture the server cert info.
  2191. //
  2192. __try
  2193. {
  2194. // OK to copy the structure
  2195. RtlCopyMemory(pCopyCertInfo,
  2196. pCertInfo,
  2197. sizeof(HTTP_SSL_SERVER_CERT_INFO));
  2198. // Return the number of bytes read.
  2199. *pTakenLength = sizeof(HTTP_SSL_SERVER_CERT_INFO);
  2200. if (pCopyCertInfo->Cert.CertHashLength > HTTP_SSL_CERT_HASH_LENGTH)
  2201. {
  2202. ExRaiseStatus(STATUS_INVALID_PARAMETER);
  2203. }
  2204. //
  2205. // Capture Issuer list if any.
  2206. //
  2207. if (pCopyCertInfo->IssuerInfo.IssuerListLength &&
  2208. pCopyCertInfo->IssuerInfo.IssuerCount &&
  2209. pCopyCertInfo->IssuerInfo.pIssuerList)
  2210. {
  2211. // IssuerList must be accessible.
  2212. UlProbeForRead(pCopyCertInfo->IssuerInfo.pIssuerList,
  2213. pCopyCertInfo->IssuerInfo.IssuerListLength,
  2214. sizeof(ULONG),
  2215. UserMode);
  2216. // Allocate memory to store IssuerList.
  2217. pIssuerList = UL_ALLOCATE_POOL_WITH_QUOTA(
  2218. NonPagedPool,
  2219. pCopyCertInfo->IssuerInfo.IssuerListLength,
  2220. UC_SSL_CERT_DATA_POOL_TAG,
  2221. pClientConn->pServerInfo->pProcess);
  2222. if (!pIssuerList)
  2223. {
  2224. ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
  2225. }
  2226. // Copy IssuerList to allocated memory.
  2227. RtlCopyMemory(pIssuerList,
  2228. pCopyCertInfo->IssuerInfo.pIssuerList,
  2229. pCopyCertInfo->IssuerInfo.IssuerListLength);
  2230. // Fixup the pointers inside IssuerList
  2231. Status = UcpFixupIssuerList(
  2232. pIssuerList,
  2233. pCopyCertInfo->IssuerInfo.pIssuerList,
  2234. pCopyCertInfo->IssuerInfo.IssuerCount,
  2235. pCopyCertInfo->IssuerInfo.IssuerListLength);
  2236. if (!NT_SUCCESS(Status))
  2237. {
  2238. ExRaiseStatus(Status);
  2239. }
  2240. // Finally copy the pointer to the internal copy of IssuerInfo
  2241. pCopyCertInfo->IssuerInfo.pIssuerList = pIssuerList;
  2242. }
  2243. else
  2244. {
  2245. pCopyCertInfo->IssuerInfo.IssuerListLength = 0;
  2246. pCopyCertInfo->IssuerInfo.IssuerCount = 0;
  2247. pCopyCertInfo->IssuerInfo.pIssuerList = NULL;
  2248. }
  2249. //
  2250. // Serialized Certificates and Certificate stores are huge.
  2251. // Make there internal copies only if required.
  2252. //
  2253. // A copy is made in the following case:
  2254. // 1. if an issuer list is specified
  2255. // 2. if the new certificate is different from the existing one
  2256. //
  2257. if (pIssuerList != NULL ||
  2258. UcpNeedToCaptureSerializedCert(pCopyCertInfo,
  2259. pClientConn->pServerInfo))
  2260. {
  2261. // Required to copy serialized certificate.
  2262. // Initialize Flags
  2263. pCopyCertInfo->Cert.Flags = HTTP_SSL_SERIALIZED_CERT_PRESENT;
  2264. //
  2265. // Copy serialized server ceritificate
  2266. //
  2267. if (pCopyCertInfo->Cert.SerializedCertLength)
  2268. {
  2269. // Serialized cert must be accessible
  2270. UlProbeForRead(pCopyCertInfo->Cert.pSerializedCert,
  2271. pCopyCertInfo->Cert.SerializedCertLength,
  2272. sizeof(UCHAR),
  2273. UserMode);
  2274. // Allocate memory for serialized cert
  2275. pCert = UL_ALLOCATE_POOL_WITH_QUOTA(
  2276. NonPagedPool,
  2277. pCopyCertInfo->Cert.SerializedCertLength,
  2278. UC_SSL_CERT_DATA_POOL_TAG,
  2279. pClientConn->pServerInfo->pProcess);
  2280. if (!pCert)
  2281. {
  2282. ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
  2283. }
  2284. // Copy serialized cert
  2285. RtlCopyMemory(pCert,
  2286. pCopyCertInfo->Cert.pSerializedCert,
  2287. pCopyCertInfo->Cert.SerializedCertLength);
  2288. // Internal copy of the serialized cert
  2289. pCopyCertInfo->Cert.pSerializedCert = pCert;
  2290. }
  2291. else
  2292. {
  2293. pCopyCertInfo->Cert.pSerializedCert = NULL;
  2294. }
  2295. //
  2296. // Copy serialized certificate store
  2297. //
  2298. if (pCopyCertInfo->Cert.SerializedCertStoreLength)
  2299. {
  2300. // Serialized cert store must be accessible
  2301. UlProbeForRead(pCopyCertInfo->Cert.pSerializedCertStore,
  2302. pCopyCertInfo->Cert.SerializedCertStoreLength,
  2303. sizeof(UCHAR),
  2304. UserMode);
  2305. // Allocate memory for serialized cert store
  2306. pCertStore = UL_ALLOCATE_POOL_WITH_QUOTA(
  2307. NonPagedPool,
  2308. pCopyCertInfo->Cert.SerializedCertStoreLength,
  2309. UC_SSL_CERT_DATA_POOL_TAG,
  2310. pClientConn->pServerInfo->pProcess);
  2311. if (!pCertStore)
  2312. {
  2313. ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
  2314. }
  2315. // Copy serialized cert store
  2316. RtlCopyMemory(pCertStore,
  2317. pCopyCertInfo->Cert.pSerializedCertStore,
  2318. pCopyCertInfo->Cert.SerializedCertStoreLength);
  2319. // Internal copy of the serialized cert
  2320. pCopyCertInfo->Cert.pSerializedCertStore = pCertStore;
  2321. }
  2322. else
  2323. {
  2324. pCopyCertInfo->Cert.pSerializedCertStore = NULL;
  2325. }
  2326. }
  2327. else
  2328. {
  2329. // No Need to copy serialized certificate!
  2330. pCopyCertInfo->Cert.Flags = 0;
  2331. pCopyCertInfo->Cert.pSerializedCert = NULL;
  2332. pCopyCertInfo->Cert.SerializedCertLength = 0;
  2333. pCopyCertInfo->Cert.pSerializedCertStore = NULL;
  2334. pCopyCertInfo->Cert.SerializedCertStoreLength = 0;
  2335. }
  2336. }
  2337. __except(UL_EXCEPTION_FILTER())
  2338. {
  2339. Status = GetExceptionCode();
  2340. if (pIssuerList)
  2341. {
  2342. UL_FREE_POOL_WITH_QUOTA(pIssuerList,
  2343. UC_SSL_CERT_DATA_POOL_TAG,
  2344. NonPagedPool,
  2345. pCopyCertInfo->IssuerInfo.IssuerListLength,
  2346. pClientConn->pServerInfo->pProcess);
  2347. }
  2348. if (pCert)
  2349. {
  2350. UL_FREE_POOL_WITH_QUOTA(pCert,
  2351. UC_SSL_CERT_DATA_POOL_TAG,
  2352. NonPagedPool,
  2353. pCopyCertInfo->Cert.SerializedCertLength,
  2354. pClientConn->pServerInfo->pProcess);
  2355. }
  2356. if (pCertStore)
  2357. {
  2358. UL_FREE_POOL_WITH_QUOTA(
  2359. pCertStore,
  2360. UC_SSL_CERT_DATA_POOL_TAG,
  2361. NonPagedPool,
  2362. pCopyCertInfo->Cert.SerializedCertStoreLength,
  2363. pClientConn->pServerInfo->pProcess);
  2364. }
  2365. }
  2366. return Status;
  2367. }