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.

2654 lines
74 KiB

  1. /*++
  2. Copyright (c) 2001-2002 Microsoft Corporation
  3. Module Name:
  4. ServerConfig.c
  5. Abstract:
  6. Code for handling server configuration APIs.
  7. Author:
  8. Rajesh Sundaram (rajeshsu) 1-Nov-2001
  9. Revision History:
  10. Eric Stenson (ericsten) **-***-**** -- Add IP Listen support.
  11. Rajesh Sundaram (rajeshsu) 16-Apr-2002 -- Add URL ACL support.
  12. --*/
  13. #include "precomp.h"
  14. #include <stdio.h>
  15. #include <search.h>
  16. #include <Shlwapi.h>
  17. #include <sddl.h>
  18. #define HTTP_PARAM_KEY \
  19. L"System\\CurrentControlSet\\Services\\HTTP\\Parameters"
  20. #define URLACL_REGISTRY_KEY HTTP_PARAM_KEY L"\\UrlAclInfo"
  21. //
  22. // Keys for synchronizing registry access.
  23. //
  24. #define HTTP_SYNCHRONIZE_KEY HTTP_PARAM_KEY L"\\Synchronize"
  25. #define SSL_REGISTRY_KEY_SYNCHRONIZE L"SSL"
  26. #define IP_REGISTRY_KEY_SYNCHRONIZE L"IPListen"
  27. HKEY g_SynchronizeRegistryHandle;
  28. //
  29. // SSL Config
  30. //
  31. #define SSL_REGISTRY_KEY HTTP_PARAM_KEY L"\\SslBindingInfo"
  32. #define SSL_CERT_HASH L"SslCertHash"
  33. #define SSL_APPID L"AppId"
  34. #define SSL_CERT_STORE_NAME L"SslCertStoreName"
  35. #define SSL_CERT_CHECK_MODE L"DefaultSslCertCheckMode"
  36. #define SSL_REVOCATION_FRESHNESS_TIME L"DefaultSslRevocationFreshnessTime"
  37. #define SSL_REVOCATION_URL_RETRIEVAL_TIMEOUT \
  38. L"DefaultSslRevocationUrlRetrievalTimeout"
  39. #define SSL_CTL_IDENTIFIER L"DefaultSslCtlIdentifier"
  40. #define SSL_CTL_STORENAME L"DefaultSslCtlStoreName"
  41. #define SSL_FLAGS L"DefaultFlags"
  42. HKEY g_SslRegistryHandle;
  43. HANDLE g_ServiceControlChannelHandle;
  44. HKEY g_UrlAclRegistryHandle;
  45. //
  46. // IP Listen Only Config
  47. //
  48. #define IP_LISTEN_ONLY_VALUE L"ListenOnlyList"
  49. //
  50. // Macros.
  51. //
  52. // NOTE: REG_QUERY_VALUE will not raise an exception for ERROR_FILE_NOT_FOUND
  53. // because not all parameters are mandatory (e.g. SslCtlIdentifier).
  54. #define REG_QUERY_VALUE(Status, Handle, Value, pBuffer, BytesAvail) \
  55. { \
  56. (Status) = RegQueryValueEx( \
  57. (Handle), \
  58. (Value), \
  59. 0, \
  60. NULL, \
  61. (PVOID)(pBuffer), \
  62. &(BytesAvail) \
  63. ); \
  64. \
  65. if((Status) != NO_ERROR && (Status) != ERROR_FILE_NOT_FOUND) \
  66. { \
  67. __leave; \
  68. } \
  69. }
  70. #define ADVANCE_BUFFER(Status, pSrc, lSrc, pBuffer, BytesAvail, pWritten) \
  71. { \
  72. if((Status) == NO_ERROR) \
  73. { \
  74. (pSrc) = (PVOID)(pBuffer); \
  75. (lSrc) = (BytesAvail); \
  76. *(pWritten) += ALIGN_UP((BytesAvail), PVOID); \
  77. (pBuffer) += ALIGN_UP((BytesAvail), PVOID); \
  78. } \
  79. }
  80. #define REG_SET_VALUE(Status, Handle, Value, Type, pBuffer, Length) \
  81. { \
  82. (Status) = RegSetValueEx((Handle), \
  83. (Value), \
  84. 0, \
  85. (Type), \
  86. (PVOID)(pBuffer), \
  87. (Length) \
  88. ); \
  89. if((Status) != ERROR_SUCCESS) \
  90. { \
  91. __leave; \
  92. } \
  93. }
  94. #define REG_SET_SZ(Status, Handle, Value, pBuffer) \
  95. { \
  96. if((pBuffer)) \
  97. { \
  98. REG_SET_VALUE((Status), \
  99. (Handle), \
  100. (Value), \
  101. REG_SZ, \
  102. (pBuffer), \
  103. (ULONG)(wcslen((pBuffer)) + 1) * sizeof(WCHAR) \
  104. ); \
  105. } \
  106. }
  107. //
  108. // Internal Functions.
  109. //
  110. DWORD
  111. ComputeSockAddrLength(
  112. IN PSOCKADDR pSockAddr
  113. )
  114. {
  115. DWORD dwLength;
  116. switch(pSockAddr->sa_family)
  117. {
  118. case AF_INET:
  119. dwLength = sizeof(SOCKADDR_IN);
  120. break;
  121. case AF_INET6:
  122. dwLength = sizeof(SOCKADDR_IN6);
  123. break;
  124. default:
  125. dwLength = 0;
  126. break;
  127. }
  128. return dwLength;
  129. }
  130. /***************************************************************************++
  131. Routine Description:
  132. Performs initialization of the configuration globals.
  133. Arguments:
  134. None.
  135. Return Value:
  136. Success/Failure.
  137. --***************************************************************************/
  138. ULONG
  139. InitializeConfigurationGlobals()
  140. {
  141. ULONG Status, Disposition;
  142. WORD wVersionRequested;
  143. WSADATA wsaData;
  144. //
  145. // Init to NULL
  146. //
  147. g_SynchronizeRegistryHandle = NULL;
  148. g_SslRegistryHandle = NULL;
  149. wVersionRequested = MAKEWORD( 2, 2 );
  150. if(WSAStartup( wVersionRequested, &wsaData ) != 0)
  151. {
  152. return GetLastError();
  153. }
  154. //
  155. // Create the SSL registry key.
  156. //
  157. Status = RegCreateKeyEx(
  158. HKEY_LOCAL_MACHINE,
  159. SSL_REGISTRY_KEY,
  160. 0,
  161. NULL,
  162. REG_OPTION_NON_VOLATILE,
  163. KEY_READ | KEY_WRITE,
  164. NULL,
  165. &g_SslRegistryHandle,
  166. &Disposition
  167. );
  168. if(NO_ERROR != Status)
  169. {
  170. TerminateConfigurationGlobals();
  171. return Status;
  172. }
  173. //
  174. // Create the Synchronize registry key.
  175. //
  176. Status = RegCreateKeyEx(
  177. HKEY_LOCAL_MACHINE,
  178. HTTP_SYNCHRONIZE_KEY,
  179. 0,
  180. NULL,
  181. REG_OPTION_VOLATILE,
  182. KEY_READ | KEY_WRITE,
  183. NULL,
  184. &g_SynchronizeRegistryHandle,
  185. &Disposition
  186. );
  187. if(NO_ERROR != Status)
  188. {
  189. TerminateConfigurationGlobals();
  190. return Status;
  191. }
  192. //
  193. // URL ACL registry key.
  194. //
  195. Status = RegCreateKeyEx(
  196. HKEY_LOCAL_MACHINE,
  197. URLACL_REGISTRY_KEY,
  198. 0,
  199. NULL,
  200. REG_OPTION_NON_VOLATILE,
  201. KEY_READ | KEY_WRITE,
  202. NULL,
  203. &g_UrlAclRegistryHandle,
  204. &Disposition
  205. );
  206. if(NO_ERROR != Status)
  207. {
  208. TerminateConfigurationGlobals();
  209. return Status;
  210. }
  211. //
  212. // Control channel for URL ACL.
  213. //
  214. Status = OpenAndEnableControlChannel(&g_ServiceControlChannelHandle);
  215. if(NO_ERROR != Status)
  216. {
  217. TerminateConfigurationGlobals();
  218. return Status;
  219. }
  220. return Status;
  221. }
  222. /***************************************************************************++
  223. Routine Description:
  224. Performs termination of the configuration globals.
  225. Arguments:
  226. None.
  227. Return Value:
  228. None.
  229. --***************************************************************************/
  230. VOID
  231. TerminateConfigurationGlobals(VOID)
  232. {
  233. WSACleanup();
  234. if(g_SynchronizeRegistryHandle)
  235. {
  236. RegCloseKey(g_SynchronizeRegistryHandle);
  237. g_SynchronizeRegistryHandle = NULL;
  238. }
  239. if(g_SslRegistryHandle)
  240. {
  241. RegCloseKey(g_SslRegistryHandle);
  242. g_SslRegistryHandle = NULL;
  243. }
  244. if(g_UrlAclRegistryHandle)
  245. {
  246. RegCloseKey(g_UrlAclRegistryHandle);
  247. g_UrlAclRegistryHandle = NULL;
  248. }
  249. if(g_ServiceControlChannelHandle)
  250. {
  251. CloseHandle(g_ServiceControlChannelHandle);
  252. g_ServiceControlChannelHandle = NULL;
  253. }
  254. }
  255. /***************************************************************************++
  256. Routine Description:
  257. Acquires a process wide mutex (for interprocess synchronization). We could
  258. make this into a MRSW lock, but that's not going to help us a whole lot
  259. since Set/Delete are rare operations & there is only one reader.
  260. Arguments:
  261. None.
  262. Return Value:
  263. None.
  264. --***************************************************************************/
  265. _inline
  266. DWORD
  267. AcquireHttpRegistryMutex(
  268. PWCHAR pKey
  269. )
  270. {
  271. DWORD Status;
  272. DWORD Disposition;
  273. HKEY SubKeyHandle;
  274. HANDLE hEvent = NULL;
  275. for(;;)
  276. {
  277. Status = RegCreateKeyEx(
  278. g_SynchronizeRegistryHandle,
  279. pKey,
  280. 0,
  281. NULL,
  282. REG_OPTION_VOLATILE,
  283. KEY_READ | KEY_WRITE,
  284. NULL,
  285. &SubKeyHandle,
  286. &Disposition
  287. );
  288. if(Status != ERROR_SUCCESS)
  289. {
  290. return Status;
  291. }
  292. RegCloseKey(SubKeyHandle);
  293. if(Disposition == REG_OPENED_EXISTING_KEY)
  294. {
  295. // Some other thread has acquired the lock. We'll wait till we
  296. // own the lock. In order to do this, we register for change
  297. // notification for g_SynchronizeRegistryHandle (i.e the owner
  298. // thread deletes the HTTP_SYNCHRONIZE_KEY key).
  299. //
  300. // Now, there are two issues here. There could be a race where
  301. // the key gets deleted just before we call RegNotifyChangeKeyValue
  302. // In order to protect from this, we add a timeout to the Wait
  303. // routine.
  304. //
  305. // Secondly, we could get woken when the app changes other parts
  306. // of the registry under g_SynchronizeRegistryHandle. However,
  307. // since Sets & deletes are not common operations, this is OK.
  308. //
  309. // We don't care about the return value of RegNotifyChangeKeyValue
  310. // If it fails, we'll just wait till the timeout expires.
  311. //
  312. if(!hEvent)
  313. {
  314. hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  315. if(!hEvent)
  316. {
  317. return GetLastError();
  318. }
  319. }
  320. RegNotifyChangeKeyValue(
  321. g_SynchronizeRegistryHandle,
  322. TRUE,
  323. REG_NOTIFY_CHANGE_NAME,
  324. hEvent,
  325. TRUE
  326. );
  327. if(WaitForSingleObject(
  328. hEvent,
  329. 10000 // 10 seconds.
  330. ) == WAIT_FAILED)
  331. {
  332. CloseHandle(hEvent);
  333. return GetLastError();
  334. }
  335. }
  336. else
  337. {
  338. // We've acquired the lock.
  339. break;
  340. }
  341. }
  342. if(hEvent)
  343. {
  344. CloseHandle(hEvent);
  345. }
  346. return ERROR_SUCCESS;
  347. }
  348. /***************************************************************************++
  349. Routine Description:
  350. Releases a process wide mutex (for interprocess synchronization)
  351. Arguments:
  352. None.
  353. Return Value:
  354. None.
  355. --***************************************************************************/
  356. _inline
  357. VOID
  358. ReleaseHttpRegistryMutex(
  359. IN PWCHAR pKey
  360. )
  361. {
  362. RegDeleteKey(g_SynchronizeRegistryHandle, pKey);
  363. }
  364. /***************************************************************************++
  365. Routine Description:
  366. Internal function that sets SSL configuration.
  367. Arguments:
  368. pConfigInformation - pointer to HTTP_SERVICE_CONFIG_SSL_SET
  369. ConfigInformationLength - length of input buffer.
  370. Return Value:
  371. Win32 error code.
  372. --***************************************************************************/
  373. ULONG
  374. SetSslServiceConfiguration(
  375. IN PVOID pConfigInformation,
  376. IN ULONG ConfigInformationLength
  377. )
  378. {
  379. ULONG Status = NO_ERROR;
  380. HKEY SubKeyHandle = NULL;
  381. PHTTP_SERVICE_CONFIG_SSL_SET pSslConfig;
  382. WCHAR IpAddrBuff[MAX_PATH];
  383. DWORD dwIpAddrLength, Disposition;
  384. DWORD dwSockAddrLength;
  385. BOOLEAN bDeleteCreatedKey = FALSE;
  386. //
  387. // Parameter validation.
  388. //
  389. pSslConfig = (PHTTP_SERVICE_CONFIG_SSL_SET) pConfigInformation;
  390. if(!pSslConfig ||
  391. ConfigInformationLength != sizeof(HTTP_SERVICE_CONFIG_SSL_SET))
  392. {
  393. return ERROR_INVALID_PARAMETER;
  394. }
  395. // acquire the mutex to prevent other processes from reading this
  396. // since we are acquiring a machine wide mutex, we need to ensure
  397. // that we release the mutex if the app passes bad parameters.
  398. // Acquire the mutex.
  399. __try
  400. {
  401. if((Status =
  402. AcquireHttpRegistryMutex(SSL_REGISTRY_KEY_SYNCHRONIZE)) != NO_ERROR)
  403. {
  404. __leave;
  405. }
  406. // Convert the address into a string.
  407. //
  408. dwIpAddrLength = MAX_PATH;
  409. dwSockAddrLength = ComputeSockAddrLength(pSslConfig->KeyDesc.pIpPort);
  410. if(dwSockAddrLength == 0)
  411. {
  412. Status = ERROR_NOT_SUPPORTED;
  413. __leave;
  414. }
  415. Status = WSAAddressToString(
  416. pSslConfig->KeyDesc.pIpPort,
  417. dwSockAddrLength,
  418. NULL,
  419. IpAddrBuff,
  420. &dwIpAddrLength
  421. );
  422. if(Status != NO_ERROR)
  423. {
  424. __leave;
  425. }
  426. // First, we try to create the IP:port. If this already exists,
  427. // we'll bail.
  428. Status = RegCreateKeyEx(
  429. g_SslRegistryHandle,
  430. IpAddrBuff,
  431. 0,
  432. NULL,
  433. REG_OPTION_NON_VOLATILE,
  434. KEY_READ | KEY_WRITE,
  435. NULL,
  436. &SubKeyHandle,
  437. &Disposition
  438. );
  439. if(Status != ERROR_SUCCESS)
  440. {
  441. __leave;
  442. }
  443. if(Disposition == REG_OPENED_EXISTING_KEY)
  444. {
  445. Status = ERROR_ALREADY_EXISTS;
  446. __leave;
  447. }
  448. //
  449. // Any errors from now onwards should delete the key.
  450. //
  451. bDeleteCreatedKey = TRUE;
  452. //
  453. // REG_BINARY: Cert Hash
  454. //
  455. REG_SET_VALUE(Status,
  456. SubKeyHandle,
  457. SSL_CERT_HASH,
  458. REG_BINARY,
  459. pSslConfig->ParamDesc.pSslHash,
  460. pSslConfig->ParamDesc.SslHashLength
  461. );
  462. //
  463. // REG_BINARY: AppID
  464. //
  465. REG_SET_VALUE(Status,
  466. SubKeyHandle,
  467. SSL_APPID,
  468. REG_BINARY,
  469. &pSslConfig->ParamDesc.AppId,
  470. sizeof(pSslConfig->ParamDesc.AppId)
  471. );
  472. //
  473. // REG_DWORD: The Cert Check Mode.
  474. //
  475. REG_SET_VALUE(Status,
  476. SubKeyHandle,
  477. SSL_CERT_CHECK_MODE,
  478. REG_DWORD,
  479. &pSslConfig->ParamDesc.DefaultCertCheckMode,
  480. sizeof(pSslConfig->ParamDesc.DefaultCertCheckMode)
  481. );
  482. //
  483. // REG_DWORD: The revocation freshness time
  484. //
  485. REG_SET_VALUE(
  486. Status,
  487. SubKeyHandle,
  488. SSL_REVOCATION_FRESHNESS_TIME,
  489. REG_DWORD,
  490. &pSslConfig->ParamDesc.DefaultRevocationFreshnessTime,
  491. sizeof(pSslConfig->ParamDesc.DefaultRevocationFreshnessTime)
  492. );
  493. //
  494. // REG_DWORD: The URL Retrieval Timeout
  495. //
  496. REG_SET_VALUE(
  497. Status,
  498. SubKeyHandle,
  499. SSL_REVOCATION_URL_RETRIEVAL_TIMEOUT,
  500. REG_DWORD,
  501. &pSslConfig->ParamDesc.DefaultRevocationUrlRetrievalTimeout,
  502. sizeof(pSslConfig->ParamDesc.DefaultRevocationUrlRetrievalTimeout)
  503. );
  504. //
  505. // REG_DWORD: SSL Flags
  506. //
  507. REG_SET_VALUE(Status,
  508. SubKeyHandle,
  509. SSL_FLAGS,
  510. REG_DWORD,
  511. &pSslConfig->ParamDesc.DefaultFlags,
  512. sizeof(pSslConfig->ParamDesc.DefaultFlags)
  513. );
  514. //
  515. // REG_SZ: The Cert Store name.
  516. //
  517. REG_SET_SZ(Status,
  518. SubKeyHandle,
  519. SSL_CERT_STORE_NAME,
  520. pSslConfig->ParamDesc.pSslCertStoreName
  521. );
  522. //
  523. // REG_SZ: The CTL Identifier
  524. //
  525. REG_SET_SZ(Status,
  526. SubKeyHandle,
  527. SSL_CTL_IDENTIFIER,
  528. pSslConfig->ParamDesc.pDefaultSslCtlIdentifier
  529. );
  530. //
  531. // REG_SZ: The CTL Store name.
  532. //
  533. REG_SET_SZ(Status,
  534. SubKeyHandle,
  535. SSL_CTL_STORENAME,
  536. pSslConfig->ParamDesc.pDefaultSslCtlStoreName
  537. );
  538. }
  539. __finally
  540. {
  541. if(SubKeyHandle)
  542. {
  543. RegCloseKey(SubKeyHandle);
  544. SubKeyHandle = NULL;
  545. }
  546. if(Status != NO_ERROR && bDeleteCreatedKey)
  547. {
  548. // Recursively delete subkeys & all descendents.
  549. SHDeleteKey(g_SslRegistryHandle, IpAddrBuff);
  550. }
  551. // Free the mutex.
  552. //
  553. ReleaseHttpRegistryMutex(SSL_REGISTRY_KEY_SYNCHRONIZE);
  554. }
  555. return Status;
  556. }
  557. /***************************************************************************++
  558. Routine Description:
  559. Internal function that deletes SSL configuration.
  560. Arguments:
  561. pConfigInformation - pointer to HTTP_SERVICE_CONFIG_SSL_SET
  562. ConfigInformationLength - length of input buffer.
  563. Return Value:
  564. Win32 error code.
  565. --***************************************************************************/
  566. ULONG
  567. DeleteSslServiceConfiguration(
  568. IN PVOID pConfigInformation,
  569. IN ULONG ConfigInformationLength
  570. )
  571. {
  572. ULONG Status = NO_ERROR;
  573. PHTTP_SERVICE_CONFIG_SSL_SET pSslConfig;
  574. WCHAR IpAddrBuff[MAX_PATH];
  575. DWORD dwIpAddrLength;
  576. DWORD dwSockAddrLength;
  577. //
  578. // Parameter validation.
  579. //
  580. pSslConfig = (PHTTP_SERVICE_CONFIG_SSL_SET) pConfigInformation;
  581. if(!pSslConfig ||
  582. ConfigInformationLength != sizeof(HTTP_SERVICE_CONFIG_SSL_SET))
  583. {
  584. return ERROR_INVALID_PARAMETER;
  585. }
  586. // acquire the mutex to prevent other processes from reading this
  587. // since we are acquiring a machine wide mutex, we need to ensure
  588. // that we release the mutex if the app passes bad parameters.
  589. __try
  590. {
  591. if((Status =
  592. AcquireHttpRegistryMutex(SSL_REGISTRY_KEY_SYNCHRONIZE)) != NO_ERROR)
  593. {
  594. __leave;
  595. }
  596. // Convert the address into a string.
  597. //
  598. dwIpAddrLength = MAX_PATH;
  599. dwSockAddrLength = ComputeSockAddrLength(pSslConfig->KeyDesc.pIpPort);
  600. if(dwSockAddrLength == 0)
  601. {
  602. Status = ERROR_NOT_SUPPORTED;
  603. __leave;
  604. }
  605. Status = WSAAddressToString(
  606. pSslConfig->KeyDesc.pIpPort,
  607. dwSockAddrLength,
  608. NULL,
  609. IpAddrBuff,
  610. &dwIpAddrLength
  611. );
  612. if(Status != NO_ERROR)
  613. {
  614. __leave;
  615. }
  616. //
  617. // Recursively delete all subkeys under this.
  618. //
  619. Status = SHDeleteKey(g_SslRegistryHandle, IpAddrBuff);
  620. }
  621. __finally
  622. {
  623. // Free the mutex.
  624. //
  625. ReleaseHttpRegistryMutex(SSL_REGISTRY_KEY_SYNCHRONIZE);
  626. }
  627. return Status;
  628. }
  629. /***************************************************************************++
  630. Routine Description:
  631. Internal function that queries SSL configuration for a exact match. This
  632. routine is called with the SSL Mutex acquired.
  633. Arguments:
  634. pInput - pointer to HTTP_SERVICE_CONFIG_SSL_QUERY
  635. InputLength - length of input buffer.
  636. pOutput - pointer to output buffer
  637. OutputLength - sizeof output buffer
  638. pReturnLength - Bytes written/needed.
  639. Return Value:
  640. Win32 error code.
  641. --***************************************************************************/
  642. ULONG
  643. QuerySslServiceConfigurationExact(
  644. IN PWCHAR lpszIpAddrBuff,
  645. IN PCHAR pBuffer,
  646. OUT PULONG pReturnLength,
  647. IN ULONG BytesAvailable
  648. )
  649. {
  650. DWORD Status = NO_ERROR;
  651. HKEY SubKeyHandle = NULL;
  652. DWORD dwSockAddrLength = sizeof(SOCKADDR_STORAGE);
  653. DWORD BytesRequired, ValueCount, MaxValueLength;
  654. PHTTP_SERVICE_CONFIG_SSL_SET pSslSet;
  655. //
  656. // Validate output parameters.
  657. //
  658. pSslSet = (PHTTP_SERVICE_CONFIG_SSL_SET) pBuffer;
  659. Status = RegOpenKeyEx(
  660. g_SslRegistryHandle,
  661. lpszIpAddrBuff,
  662. 0,
  663. KEY_READ | KEY_WRITE,
  664. &SubKeyHandle
  665. );
  666. if(Status != ERROR_SUCCESS)
  667. {
  668. return Status;
  669. }
  670. __try
  671. {
  672. Status = RegQueryInfoKey(
  673. SubKeyHandle,
  674. NULL, // class buffer
  675. 0, // sizeof class buffer
  676. NULL, // reserved
  677. NULL, // # of subkeys
  678. NULL, // longest subkey name
  679. NULL, // longest class string
  680. &ValueCount, // # of value entries.
  681. NULL, // longest value name
  682. &MaxValueLength, // longest value data
  683. NULL, // security descriptor length
  684. NULL // last write time
  685. );
  686. if(Status != ERROR_SUCCESS)
  687. {
  688. __leave;
  689. }
  690. //
  691. // MaxValueLength does not include the size of the NULL terminator,
  692. // so let's compensate for that.
  693. //
  694. MaxValueLength += sizeof(WCHAR);
  695. //
  696. // We'll assume that all the Value's under SubKey are of MaxValueLength
  697. // that keeps things a lot simpler.
  698. //
  699. BytesRequired = dwSockAddrLength +
  700. sizeof(HTTP_SERVICE_CONFIG_SSL_SET) +
  701. (ValueCount * ALIGN_UP(MaxValueLength, PVOID));
  702. if(pBuffer == NULL || BytesAvailable < BytesRequired)
  703. {
  704. *pReturnLength = BytesRequired;
  705. Status = ERROR_INSUFFICIENT_BUFFER;
  706. __leave;
  707. }
  708. ZeroMemory(pSslSet, sizeof(HTTP_SERVICE_CONFIG_SSL_SET));
  709. pBuffer += sizeof(HTTP_SERVICE_CONFIG_SSL_SET);
  710. *pReturnLength = sizeof(HTTP_SERVICE_CONFIG_SSL_SET);
  711. //
  712. // Set up SOCKET_ADDRESS.
  713. //
  714. pSslSet->KeyDesc.pIpPort = (LPSOCKADDR)pBuffer;
  715. // Convert the IP address into SOCKADDR
  716. //
  717. // First, we try v4
  718. Status = WSAStringToAddress(
  719. lpszIpAddrBuff,
  720. AF_INET,
  721. NULL,
  722. pSslSet->KeyDesc.pIpPort,
  723. (LPINT) &dwSockAddrLength
  724. );
  725. if(Status != NO_ERROR)
  726. {
  727. dwSockAddrLength = sizeof(SOCKADDR_STORAGE);
  728. Status = WSAStringToAddress(
  729. lpszIpAddrBuff,
  730. AF_INET6,
  731. NULL,
  732. pSslSet->KeyDesc.pIpPort,
  733. (LPINT)&dwSockAddrLength
  734. );
  735. if(Status != NO_ERROR)
  736. {
  737. Status = GetLastError();
  738. __leave;
  739. }
  740. }
  741. pBuffer += sizeof(SOCKADDR_STORAGE);
  742. *pReturnLength += sizeof(SOCKADDR_STORAGE);
  743. //
  744. // Query SSL HASH.
  745. //
  746. BytesAvailable = MaxValueLength;
  747. REG_QUERY_VALUE(Status,
  748. SubKeyHandle,
  749. SSL_CERT_HASH,
  750. pBuffer,
  751. BytesAvailable
  752. );
  753. ADVANCE_BUFFER(Status,
  754. pSslSet->ParamDesc.pSslHash,
  755. pSslSet->ParamDesc.SslHashLength,
  756. pBuffer,
  757. BytesAvailable,
  758. pReturnLength
  759. );
  760. //
  761. // Query pSslCertStoreName
  762. //
  763. BytesAvailable = MaxValueLength;
  764. REG_QUERY_VALUE(Status,
  765. SubKeyHandle,
  766. SSL_CERT_STORE_NAME,
  767. pBuffer,
  768. BytesAvailable
  769. );
  770. ADVANCE_BUFFER(Status,
  771. pSslSet->ParamDesc.pSslCertStoreName,
  772. BytesAvailable,
  773. pBuffer,
  774. BytesAvailable,
  775. pReturnLength
  776. );
  777. //
  778. // Query pDefaultSslCtlIdentifier
  779. //
  780. BytesAvailable = MaxValueLength;
  781. REG_QUERY_VALUE(Status,
  782. SubKeyHandle,
  783. SSL_CTL_IDENTIFIER,
  784. pBuffer,
  785. BytesAvailable
  786. );
  787. ADVANCE_BUFFER(Status,
  788. pSslSet->ParamDesc.pDefaultSslCtlIdentifier,
  789. BytesAvailable,
  790. pBuffer,
  791. BytesAvailable,
  792. pReturnLength
  793. );
  794. //
  795. // Query pDefaultSslCtlStoreName
  796. //
  797. BytesAvailable = MaxValueLength;
  798. REG_QUERY_VALUE(Status,
  799. SubKeyHandle,
  800. SSL_CTL_STORENAME,
  801. pBuffer,
  802. BytesAvailable
  803. );
  804. ADVANCE_BUFFER(Status,
  805. pSslSet->ParamDesc.pDefaultSslCtlStoreName,
  806. BytesAvailable,
  807. pBuffer,
  808. BytesAvailable,
  809. pReturnLength
  810. );
  811. //
  812. // NOTE: when querying DWORDs, we don't have to call ADVANCE_BUFFER
  813. // as we use the space provided in the structure itself.
  814. //
  815. //
  816. // Query DefaultCertCheckMode
  817. //
  818. BytesAvailable = sizeof(pSslSet->ParamDesc.DefaultCertCheckMode);
  819. REG_QUERY_VALUE(Status,
  820. SubKeyHandle,
  821. SSL_CERT_CHECK_MODE,
  822. &pSslSet->ParamDesc.DefaultCertCheckMode,
  823. BytesAvailable
  824. );
  825. //
  826. // Query RevocationFreshnessTime
  827. //
  828. BytesAvailable =
  829. sizeof(pSslSet->ParamDesc.DefaultRevocationFreshnessTime);
  830. REG_QUERY_VALUE(Status,
  831. SubKeyHandle,
  832. SSL_REVOCATION_FRESHNESS_TIME,
  833. &pSslSet->ParamDesc.DefaultRevocationFreshnessTime,
  834. BytesAvailable
  835. );
  836. //
  837. // Query RevocationUrlRetrievalTimeout
  838. //
  839. BytesAvailable =
  840. sizeof(pSslSet->ParamDesc.DefaultRevocationUrlRetrievalTimeout);
  841. REG_QUERY_VALUE(
  842. Status,
  843. SubKeyHandle,
  844. SSL_REVOCATION_URL_RETRIEVAL_TIMEOUT,
  845. &pSslSet->ParamDesc.DefaultRevocationUrlRetrievalTimeout,
  846. BytesAvailable
  847. );
  848. //
  849. // Query DefaultFlags
  850. //
  851. BytesAvailable = sizeof(pSslSet->ParamDesc.DefaultFlags);
  852. REG_QUERY_VALUE(Status,
  853. SubKeyHandle,
  854. SSL_FLAGS,
  855. &pSslSet->ParamDesc.DefaultFlags,
  856. BytesAvailable
  857. );
  858. //
  859. // Query the AppId.
  860. //
  861. BytesAvailable = sizeof(GUID);
  862. REG_QUERY_VALUE(Status,
  863. SubKeyHandle,
  864. SSL_APPID,
  865. &pSslSet->ParamDesc.AppId,
  866. BytesAvailable
  867. );
  868. //
  869. // If the last REG_QUERY_VALUE returned an error, we'll consume it.
  870. // Some of these registry parameters are optional so we don't want to
  871. // fail the API with FILE_NOT_FOUND.
  872. //
  873. Status = NO_ERROR;
  874. }
  875. __finally
  876. {
  877. if(SubKeyHandle)
  878. {
  879. RegCloseKey(SubKeyHandle);
  880. }
  881. }
  882. return Status;
  883. }
  884. /***************************************************************************++
  885. Routine Description:
  886. Internal function that queries SSL configuration.
  887. Arguments:
  888. pInput - pointer to HTTP_SERVICE_CONFIG_SSL_QUERY
  889. InputLength - length of input buffer.
  890. pOutput - pointer to output buffer
  891. OutputLength - sizeof output buffer
  892. pReturnLength - Bytes written/needed.
  893. Return Value:
  894. Win32 error code.
  895. --***************************************************************************/
  896. ULONG
  897. QuerySslServiceConfiguration(
  898. IN PVOID pInputConfigInfo,
  899. IN ULONG InputLength,
  900. IN PVOID pOutput,
  901. IN ULONG OutputLength,
  902. OUT PULONG pReturnLength
  903. )
  904. {
  905. ULONG Status = NO_ERROR;
  906. PHTTP_SERVICE_CONFIG_SSL_QUERY pSslQuery;
  907. WCHAR IpAddrBuff[MAX_PATH];
  908. DWORD dwSize, dwIndex;
  909. FILETIME FileTime;
  910. DWORD dwIpAddrLength;
  911. DWORD dwSockAddrLength;
  912. pSslQuery = (PHTTP_SERVICE_CONFIG_SSL_QUERY) pInputConfigInfo;
  913. //
  914. // Validate input parameters.
  915. //
  916. if(pSslQuery == NULL ||
  917. InputLength != sizeof(HTTP_SERVICE_CONFIG_SSL_QUERY))
  918. {
  919. return ERROR_INVALID_PARAMETER;
  920. }
  921. __try
  922. {
  923. if((Status =
  924. AcquireHttpRegistryMutex(SSL_REGISTRY_KEY_SYNCHRONIZE)) != NO_ERROR)
  925. {
  926. __leave;
  927. }
  928. switch(pSslQuery->QueryDesc)
  929. {
  930. case HttpServiceConfigQueryExact:
  931. {
  932. //
  933. // Convert the address into a string.
  934. //
  935. dwIpAddrLength = MAX_PATH;
  936. dwSockAddrLength = ComputeSockAddrLength(
  937. pSslQuery->KeyDesc.pIpPort
  938. );
  939. if(dwSockAddrLength == 0)
  940. {
  941. Status = ERROR_NOT_SUPPORTED;
  942. __leave;
  943. }
  944. Status = WSAAddressToString(
  945. pSslQuery->KeyDesc.pIpPort,
  946. dwSockAddrLength,
  947. NULL,
  948. IpAddrBuff,
  949. &dwIpAddrLength
  950. );
  951. if(Status != NO_ERROR)
  952. {
  953. break;
  954. }
  955. Status = QuerySslServiceConfigurationExact(
  956. IpAddrBuff,
  957. pOutput,
  958. pReturnLength,
  959. OutputLength
  960. );
  961. break;
  962. }
  963. case HttpServiceConfigQueryNext:
  964. {
  965. dwIndex = pSslQuery->dwToken;
  966. dwSize = MAX_PATH;
  967. Status = RegEnumKeyEx(
  968. g_SslRegistryHandle,
  969. dwIndex,
  970. IpAddrBuff,
  971. &dwSize,
  972. NULL,
  973. NULL,
  974. NULL,
  975. &FileTime
  976. );
  977. if(Status != NO_ERROR)
  978. {
  979. break;
  980. }
  981. Status = QuerySslServiceConfigurationExact(
  982. IpAddrBuff,
  983. pOutput,
  984. pReturnLength,
  985. OutputLength
  986. );
  987. if(Status != NO_ERROR)
  988. {
  989. break;
  990. }
  991. break;
  992. }
  993. default:
  994. {
  995. Status = ERROR_INVALID_PARAMETER;
  996. break;
  997. }
  998. }
  999. }
  1000. __finally
  1001. {
  1002. // Free the mutex.
  1003. //
  1004. ReleaseHttpRegistryMutex(SSL_REGISTRY_KEY_SYNCHRONIZE);
  1005. }
  1006. return Status;
  1007. }
  1008. //
  1009. // IP Listen-Only List
  1010. //
  1011. /***************************************************************************++
  1012. Routine Description:
  1013. Internal function that adds an address to the IP Listen-Only list.
  1014. Arguments:
  1015. pConfigInformation - pointer to HTTP_SERVICE_CONFIG_IP_LISTEN_PARAM
  1016. ConfigInformationLength - length of input buffer.
  1017. Return Value:
  1018. Win32 error code.
  1019. --***************************************************************************/
  1020. ULONG
  1021. SetIpListenServiceConfiguration(
  1022. IN PVOID pConfigInformation,
  1023. IN ULONG ConfigInformationLength
  1024. )
  1025. {
  1026. DWORD Status = NO_ERROR;
  1027. HKEY SubKeyHandle = NULL;
  1028. WCHAR IpAddrBuff[MAX_PATH+1];
  1029. DWORD dwIpAddrLength;
  1030. DWORD dwValueSize;
  1031. DWORD dwType;
  1032. PWSTR pNewValue = NULL;
  1033. DWORD dwNewValueSize;
  1034. DWORD AddrCount;
  1035. DWORD i;
  1036. PWSTR pTmp;
  1037. PWSTR pTempBuffer = NULL;
  1038. PWSTR *AddrArray = NULL;
  1039. PHTTP_SERVICE_CONFIG_IP_LISTEN_PARAM pIpListenParam;
  1040. //
  1041. // Validate params.
  1042. //
  1043. if ( !pConfigInformation ||
  1044. ConfigInformationLength != sizeof(HTTP_SERVICE_CONFIG_IP_LISTEN_PARAM) )
  1045. {
  1046. return ERROR_INVALID_PARAMETER;
  1047. }
  1048. pIpListenParam = (PHTTP_SERVICE_CONFIG_IP_LISTEN_PARAM) pConfigInformation;
  1049. if ( !pIpListenParam->AddrLength ||
  1050. !pIpListenParam->pAddress )
  1051. {
  1052. return ERROR_INVALID_PARAMETER;
  1053. }
  1054. __try
  1055. {
  1056. if((Status =
  1057. AcquireHttpRegistryMutex(IP_REGISTRY_KEY_SYNCHRONIZE)) != NO_ERROR)
  1058. {
  1059. __leave;
  1060. }
  1061. //
  1062. // Convert the address into a string.
  1063. //
  1064. dwIpAddrLength = MAX_PATH;
  1065. Status = WSAAddressToString(
  1066. pIpListenParam->pAddress,
  1067. pIpListenParam->AddrLength,
  1068. NULL,
  1069. IpAddrBuff,
  1070. &dwIpAddrLength // in chars, including NULL.
  1071. );
  1072. if ( SOCKET_ERROR == Status )
  1073. {
  1074. Status = WSAGetLastError();
  1075. __leave;
  1076. }
  1077. // finesse: add double null now
  1078. IpAddrBuff[dwIpAddrLength] = L'\0';
  1079. //
  1080. // open HTTP parameters reg key
  1081. //
  1082. Status = RegOpenKeyEx(
  1083. HKEY_LOCAL_MACHINE,
  1084. HTTP_PARAM_KEY,
  1085. 0,
  1086. KEY_READ | KEY_WRITE,
  1087. &SubKeyHandle
  1088. );
  1089. if ( Status != ERROR_SUCCESS )
  1090. {
  1091. // CODEWORK: add tracing.
  1092. __leave;
  1093. }
  1094. ASSERT(SubKeyHandle);
  1095. //
  1096. // query existing value
  1097. //
  1098. dwValueSize = 0;
  1099. Status = RegQueryValueEx(
  1100. SubKeyHandle, // handle to key
  1101. IP_LISTEN_ONLY_VALUE, // value name
  1102. NULL, // reserved
  1103. &dwType, // type buffer
  1104. NULL, // data buffer
  1105. &dwValueSize // size of data buffer (bytes)
  1106. );
  1107. if ( ERROR_SUCCESS == Status )
  1108. {
  1109. // There's an existing value!
  1110. if (REG_MULTI_SZ != dwType)
  1111. {
  1112. // type mismatch. fail.
  1113. Status = ERROR_DATATYPE_MISMATCH;
  1114. __leave;
  1115. }
  1116. // alloc local buffer to hold existing value plus new
  1117. // address (and its NULL)
  1118. dwNewValueSize = dwValueSize + (sizeof(WCHAR) * dwIpAddrLength);
  1119. pNewValue = ALLOC_MEM(dwNewValueSize);
  1120. if (!pNewValue)
  1121. {
  1122. Status = ERROR_NOT_ENOUGH_MEMORY;
  1123. __leave;
  1124. }
  1125. // zero-out the block (so we don't have to worry about the
  1126. // double-null at the end)
  1127. ZeroMemory(pNewValue, dwNewValueSize);
  1128. // read existing value into local buffer
  1129. Status = RegQueryValueEx(
  1130. SubKeyHandle, // handle to key
  1131. IP_LISTEN_ONLY_VALUE, // value name
  1132. NULL, // reserved
  1133. &dwType, // type buffer
  1134. (LPBYTE)pNewValue, // data buffer
  1135. &dwValueSize // size of data buffer (bytes)
  1136. );
  1137. if ( ERROR_SUCCESS != Status )
  1138. {
  1139. __leave;
  1140. }
  1141. if (REG_MULTI_SZ != dwType)
  1142. {
  1143. // type mismatch. fail.
  1144. Status = ERROR_DATATYPE_MISMATCH;
  1145. __leave;
  1146. }
  1147. // count how many strings there are
  1148. pTmp = pNewValue;
  1149. AddrCount = 0;
  1150. while ( *pTmp )
  1151. {
  1152. // check if the new addr is a dup
  1153. if ( (wcslen(pTmp) == (dwIpAddrLength - 1)) &&
  1154. (0 == wcsncmp(pTmp, IpAddrBuff, dwIpAddrLength-1)) )
  1155. {
  1156. // Dup found; bail out
  1157. Status = ERROR_ALREADY_EXISTS;
  1158. __leave;
  1159. }
  1160. // advance to next multi-sz string
  1161. pTmp += ( wcslen(pTmp) + 1 );
  1162. AddrCount ++;
  1163. }
  1164. // Add new address to end of the list
  1165. // finesse: leverage the fact that the buffer is big enough, and
  1166. // we've already double-nulled the end of the new address (hence
  1167. // the dwIpAddrLength+1)
  1168. memcpy( pTmp, IpAddrBuff, (sizeof(WCHAR) * (dwIpAddrLength+1)) );
  1169. AddrCount++;
  1170. // alloc array of pointers for quicksort
  1171. AddrArray = ALLOC_MEM( AddrCount * sizeof(PWSTR) );
  1172. if ( !AddrArray )
  1173. {
  1174. Status = ERROR_NOT_ENOUGH_MEMORY;
  1175. __leave;
  1176. }
  1177. // Init array of addresses
  1178. pTmp = pNewValue;
  1179. i = 0;
  1180. while( *pTmp )
  1181. {
  1182. AddrArray[i] = pTmp;
  1183. pTmp += ( wcslen(pTmp) + 1 );
  1184. i++;
  1185. }
  1186. // Sort Array of PWSTR pointers
  1187. // NOTE: this does not sort the array!
  1188. qsort(
  1189. AddrArray,
  1190. AddrCount,
  1191. sizeof(PWSTR),
  1192. wcscmp
  1193. );
  1194. // Alloc a temp buffer (because an in-place rearrangement is painful)
  1195. pTempBuffer = ALLOC_MEM(dwNewValueSize);
  1196. if (!pTempBuffer)
  1197. {
  1198. Status = ERROR_NOT_ENOUGH_MEMORY;
  1199. __leave;
  1200. }
  1201. pTmp = pTempBuffer;
  1202. for ( i = 0; i < AddrCount; i++ )
  1203. {
  1204. // CODEWORK: add an heuristic for checking for duplicates.
  1205. wcscpy( pTmp, AddrArray[i] );
  1206. pTmp += wcslen(AddrArray[i]) + 1;
  1207. }
  1208. // add double-null
  1209. ASSERT( (DWORD)(pTmp - pTempBuffer) < dwNewValueSize );
  1210. *pTmp = L'\0';
  1211. // set sorted value
  1212. REG_SET_VALUE(Status,
  1213. SubKeyHandle,
  1214. IP_LISTEN_ONLY_VALUE,
  1215. REG_MULTI_SZ,
  1216. pTempBuffer,
  1217. dwNewValueSize
  1218. );
  1219. FREE_MEM( pTempBuffer );
  1220. }
  1221. else
  1222. {
  1223. // No value exists!
  1224. // calc the buffer size in bytes (including the double-null)
  1225. dwValueSize = sizeof(WCHAR) * (dwIpAddrLength + 1);
  1226. // set value
  1227. // finesse: the value has already been double-null'd above.
  1228. REG_SET_VALUE(Status,
  1229. SubKeyHandle,
  1230. IP_LISTEN_ONLY_VALUE,
  1231. REG_MULTI_SZ,
  1232. IpAddrBuff,
  1233. dwValueSize
  1234. );
  1235. }
  1236. }
  1237. __finally
  1238. {
  1239. //
  1240. // close reg key
  1241. //
  1242. if ( SubKeyHandle )
  1243. {
  1244. RegCloseKey(SubKeyHandle);
  1245. }
  1246. //
  1247. // release alloc'd values
  1248. //
  1249. if ( pNewValue )
  1250. {
  1251. FREE_MEM( pNewValue );
  1252. }
  1253. if ( AddrArray )
  1254. {
  1255. FREE_MEM( AddrArray );
  1256. }
  1257. ReleaseHttpRegistryMutex(IP_REGISTRY_KEY_SYNCHRONIZE);
  1258. }
  1259. return Status;
  1260. }
  1261. /***************************************************************************++
  1262. Routine Description:
  1263. Internal function that deletes an address from the IP Listen-Only list.
  1264. Arguments:
  1265. pConfigInformation - pointer to HTTP_SERVICE_CONFIG_IP_LISTEN_PARAM
  1266. ConfigInformationLength - length of input buffer.
  1267. Return Value:
  1268. Win32 error code.
  1269. --***************************************************************************/
  1270. ULONG
  1271. DeleteIpListenServiceConfiguration(
  1272. IN PVOID pConfigInformation,
  1273. IN ULONG ConfigInformationLength
  1274. )
  1275. {
  1276. DWORD Status = NO_ERROR;
  1277. HKEY SubKeyHandle = NULL;
  1278. WCHAR IpAddrBuff[MAX_PATH];
  1279. DWORD dwIpAddrLength;
  1280. DWORD dwValueSize;
  1281. DWORD dwRemainder;
  1282. PWSTR pNewValue = NULL;
  1283. DWORD dwType;
  1284. PWSTR pTmp;
  1285. PWSTR pNext;
  1286. PHTTP_SERVICE_CONFIG_IP_LISTEN_PARAM pIpListenParam;
  1287. //
  1288. // Validate params.
  1289. //
  1290. if ( !pConfigInformation ||
  1291. ConfigInformationLength != sizeof(HTTP_SERVICE_CONFIG_IP_LISTEN_PARAM) )
  1292. {
  1293. return ERROR_INVALID_PARAMETER;
  1294. }
  1295. pIpListenParam = (PHTTP_SERVICE_CONFIG_IP_LISTEN_PARAM) pConfigInformation;
  1296. if ( !pIpListenParam->AddrLength ||
  1297. !pIpListenParam->pAddress )
  1298. {
  1299. return ERROR_INVALID_PARAMETER;
  1300. }
  1301. __try
  1302. {
  1303. if((Status =
  1304. AcquireHttpRegistryMutex(IP_REGISTRY_KEY_SYNCHRONIZE)) != NO_ERROR)
  1305. {
  1306. __leave;
  1307. }
  1308. //
  1309. // Convert the address into a string.
  1310. //
  1311. dwIpAddrLength = MAX_PATH;
  1312. Status = WSAAddressToString(
  1313. pIpListenParam->pAddress,
  1314. pIpListenParam->AddrLength,
  1315. NULL,
  1316. IpAddrBuff,
  1317. &dwIpAddrLength // in chars, including NULL.
  1318. );
  1319. if ( SOCKET_ERROR == Status )
  1320. {
  1321. Status = WSAGetLastError();
  1322. __leave;
  1323. }
  1324. //
  1325. // open HTTP parameters reg key
  1326. //
  1327. Status = RegOpenKeyEx(
  1328. HKEY_LOCAL_MACHINE,
  1329. HTTP_PARAM_KEY,
  1330. 0,
  1331. KEY_READ | KEY_WRITE,
  1332. &SubKeyHandle
  1333. );
  1334. if ( Status != ERROR_SUCCESS )
  1335. {
  1336. // CODEWORK: add tracing.
  1337. __leave;
  1338. }
  1339. ASSERT(SubKeyHandle);
  1340. //
  1341. // query existing value
  1342. //
  1343. dwValueSize = 0;
  1344. Status = RegQueryValueEx(
  1345. SubKeyHandle, // handle to key
  1346. IP_LISTEN_ONLY_VALUE, // value name
  1347. NULL, // reserved
  1348. &dwType, // type buffer
  1349. NULL, // data buffer
  1350. &dwValueSize // size of data buffer (bytes)
  1351. );
  1352. if ( ERROR_SUCCESS == Status )
  1353. {
  1354. // There's an existing value!
  1355. if (REG_MULTI_SZ != dwType)
  1356. {
  1357. // type mismatch. fail.
  1358. Status = ERROR_DATATYPE_MISMATCH;
  1359. __leave;
  1360. }
  1361. pNewValue = ALLOC_MEM(dwValueSize);
  1362. if (!pNewValue)
  1363. {
  1364. Status = ERROR_NOT_ENOUGH_MEMORY;
  1365. __leave;
  1366. }
  1367. // read existing value into local buffer
  1368. Status = RegQueryValueEx(
  1369. SubKeyHandle, // handle to key
  1370. IP_LISTEN_ONLY_VALUE, // value name
  1371. NULL, // reserved
  1372. &dwType, // type buffer
  1373. (LPBYTE)pNewValue, // data buffer
  1374. &dwValueSize // size of data buffer (bytes)
  1375. );
  1376. if ( ERROR_SUCCESS != Status )
  1377. {
  1378. __leave;
  1379. }
  1380. if (REG_MULTI_SZ != dwType)
  1381. {
  1382. // type mismatch. fail.
  1383. Status = ERROR_DATATYPE_MISMATCH;
  1384. __leave;
  1385. }
  1386. // walk value, looking for match as we go
  1387. Status = ERROR_NOT_FOUND;
  1388. pTmp = pNewValue;
  1389. while ( *pTmp )
  1390. {
  1391. // check if the new addr is a dup
  1392. if ( (wcslen(pTmp) == (dwIpAddrLength - 1)) &&
  1393. (0 == wcsncmp(pTmp, IpAddrBuff, dwIpAddrLength-1)) )
  1394. {
  1395. // Found: move suffix of values up.
  1396. pNext = pTmp + dwIpAddrLength;
  1397. dwRemainder = dwValueSize - (DWORD)((PUCHAR)pNext - (PUCHAR)pNewValue);
  1398. dwValueSize -= (dwIpAddrLength * sizeof(WCHAR));
  1399. if (dwRemainder)
  1400. {
  1401. MoveMemory(pTmp,
  1402. pNext,
  1403. dwRemainder
  1404. );
  1405. }
  1406. else
  1407. {
  1408. // removing last element on list;
  1409. // must insert trailing double-null
  1410. *pTmp = L'\0';
  1411. }
  1412. if (dwValueSize > sizeof(WCHAR))
  1413. {
  1414. // write updated value to key
  1415. REG_SET_VALUE(Status,
  1416. SubKeyHandle,
  1417. IP_LISTEN_ONLY_VALUE,
  1418. REG_MULTI_SZ,
  1419. pNewValue,
  1420. dwValueSize
  1421. );
  1422. }
  1423. else
  1424. {
  1425. // no more IPs left on list; remove the value
  1426. Status = RegDeleteValue(
  1427. SubKeyHandle,
  1428. IP_LISTEN_ONLY_VALUE
  1429. );
  1430. }
  1431. __leave;
  1432. }
  1433. // advance to next multi-sz string
  1434. pTmp += ( wcslen(pTmp) + 1 );
  1435. }
  1436. }
  1437. else
  1438. {
  1439. // No existing value, so therefore we can't delete.
  1440. Status = ERROR_NOT_FOUND;
  1441. }
  1442. }
  1443. __finally
  1444. {
  1445. ReleaseHttpRegistryMutex(IP_REGISTRY_KEY_SYNCHRONIZE);
  1446. if ( pNewValue )
  1447. {
  1448. FREE_MEM( pNewValue );
  1449. }
  1450. if (SubKeyHandle)
  1451. {
  1452. RegCloseKey(SubKeyHandle);
  1453. }
  1454. }
  1455. return Status;
  1456. }
  1457. /***************************************************************************++
  1458. Routine Description:
  1459. Internal function that queries the IP Listen-Only configuration.
  1460. This function grabs the entire list and returns it in one chunk.
  1461. Arguments:
  1462. pOutput - pointer to output buffer (point to caller provided
  1463. HTTP_SERVICE_CONFIG_IP_LISTEN_QUERY structure)
  1464. [OPTIONAL]
  1465. OutputLength - sizeof output buffer. Must be zero if pOutput is NULL.
  1466. pReturnLength - Bytes written/needed.
  1467. Return Value:
  1468. Win32 error code.
  1469. ERROR_INSUFFICIENT_BUFFER - if OutputLength cannot hold entire list.
  1470. pReturnLength will contain the required bytes.
  1471. ERROR_NOT_ENOUGH_MEMORY - Can't alloc enough memory to complete operation.
  1472. --***************************************************************************/
  1473. ULONG
  1474. QueryIpListenServiceConfiguration(
  1475. IN PVOID pOutput,
  1476. IN ULONG OutputLength,
  1477. OUT PULONG pReturnLength
  1478. )
  1479. {
  1480. DWORD Status = NO_ERROR;
  1481. HKEY SubKeyHandle = NULL;
  1482. DWORD dwValueSize;
  1483. DWORD dwSockAddrLength;
  1484. DWORD AddrCount;
  1485. DWORD BytesNeeded = 0;
  1486. PWSTR pValue = NULL;
  1487. PWSTR pTmp;
  1488. PHTTP_SERVICE_CONFIG_IP_LISTEN_QUERY pIpListenQuery;
  1489. PSOCKADDR_STORAGE pHttpAddr;
  1490. //
  1491. // Validate parameters
  1492. //
  1493. if ( pOutput &&
  1494. OutputLength < sizeof(HTTP_SERVICE_CONFIG_IP_LISTEN_QUERY) )
  1495. {
  1496. return ERROR_INVALID_PARAMETER;
  1497. }
  1498. if ( !pReturnLength )
  1499. {
  1500. return ERROR_INVALID_PARAMETER;
  1501. }
  1502. __try
  1503. {
  1504. if((Status =
  1505. AcquireHttpRegistryMutex(IP_REGISTRY_KEY_SYNCHRONIZE)) != NO_ERROR)
  1506. {
  1507. __leave;
  1508. }
  1509. //
  1510. // open HTTP parameters reg key
  1511. //
  1512. Status = RegOpenKeyEx(
  1513. HKEY_LOCAL_MACHINE,
  1514. HTTP_PARAM_KEY,
  1515. 0,
  1516. KEY_READ | KEY_WRITE,
  1517. &SubKeyHandle
  1518. );
  1519. if ( Status != ERROR_SUCCESS )
  1520. {
  1521. // CODEWORK: add tracing.
  1522. __leave;
  1523. }
  1524. ASSERT(SubKeyHandle);
  1525. //
  1526. // query existing value
  1527. //
  1528. dwValueSize = 0;
  1529. Status = RegQueryValueEx(
  1530. SubKeyHandle, // handle to key
  1531. IP_LISTEN_ONLY_VALUE, // value name
  1532. NULL, // reserved
  1533. NULL, // type buffer
  1534. NULL, // data buffer
  1535. &dwValueSize // size of data buffer (bytes)
  1536. );
  1537. if ( ERROR_SUCCESS == Status )
  1538. {
  1539. // There's an existing value!
  1540. pValue = ALLOC_MEM(dwValueSize);
  1541. if (!pValue)
  1542. {
  1543. Status = ERROR_NOT_ENOUGH_MEMORY;
  1544. __leave;
  1545. }
  1546. // read existing value into local buffer
  1547. Status = RegQueryValueEx(
  1548. SubKeyHandle, // handle to key
  1549. IP_LISTEN_ONLY_VALUE, // value name
  1550. NULL, // reserved
  1551. NULL, // type buffer
  1552. (LPBYTE)pValue, // data buffer
  1553. &dwValueSize // size of data buffer (bytes)
  1554. );
  1555. if ( ERROR_SUCCESS != Status )
  1556. {
  1557. __leave;
  1558. }
  1559. // first pass: count the number of addresses & see if we
  1560. // have enough buffer.
  1561. pTmp = pValue;
  1562. AddrCount = 0;
  1563. while ( *pTmp )
  1564. {
  1565. AddrCount++;
  1566. // advance to next multi-sz string
  1567. pTmp += ( wcslen(pTmp) + 1 );
  1568. }
  1569. if ( 0 == AddrCount )
  1570. {
  1571. // invalid. bail out.
  1572. Status = ERROR_REGISTRY_CORRUPT;
  1573. __leave;
  1574. }
  1575. // calculate bytes needed
  1576. BytesNeeded = sizeof(HTTP_SERVICE_CONFIG_IP_LISTEN_QUERY) +
  1577. (sizeof(SOCKADDR_STORAGE) * (AddrCount - 1));
  1578. // see if we have enough buffer to write out the whole mess
  1579. if ( (NULL == pOutput) ||
  1580. (OutputLength < BytesNeeded) )
  1581. {
  1582. Status = ERROR_INSUFFICIENT_BUFFER;
  1583. __leave;
  1584. }
  1585. // second pass: walk value, converting into buffer as we go
  1586. pIpListenQuery = (PHTTP_SERVICE_CONFIG_IP_LISTEN_QUERY) pOutput;
  1587. pHttpAddr = (PSOCKADDR_STORAGE) &(pIpListenQuery->AddrList[0]);
  1588. pIpListenQuery->AddrCount = AddrCount;
  1589. pTmp = pValue;
  1590. while ( *pTmp )
  1591. {
  1592. //
  1593. // Convert the IP addresses into SOCKADDRs
  1594. //
  1595. // First, we try v4
  1596. dwSockAddrLength = sizeof(SOCKADDR_STORAGE);
  1597. Status = WSAStringToAddress(
  1598. pTmp,
  1599. AF_INET,
  1600. NULL,
  1601. (LPSOCKADDR)pHttpAddr,
  1602. (LPINT)&dwSockAddrLength
  1603. );
  1604. if ( Status != NO_ERROR )
  1605. {
  1606. // Second, we try v6
  1607. dwSockAddrLength = sizeof(SOCKADDR_STORAGE);
  1608. Status = WSAStringToAddress(
  1609. pTmp,
  1610. AF_INET6,
  1611. NULL,
  1612. (LPSOCKADDR)pHttpAddr,
  1613. (LPINT)&dwSockAddrLength
  1614. );
  1615. if ( Status != NO_ERROR )
  1616. {
  1617. // if that fails, bail out; corrupt value.
  1618. Status = ERROR_REGISTRY_CORRUPT;
  1619. __leave;
  1620. }
  1621. }
  1622. // advance to next multi-sz string
  1623. pTmp += ( wcslen(pTmp) + 1 );
  1624. pHttpAddr++;
  1625. }
  1626. }
  1627. else
  1628. {
  1629. // No existing value, so therefore we can't query.
  1630. Status = ERROR_NOT_FOUND;
  1631. }
  1632. }
  1633. __finally
  1634. {
  1635. // free memory
  1636. if (pValue)
  1637. {
  1638. FREE_MEM(pValue);
  1639. }
  1640. // close reg key
  1641. if (SubKeyHandle)
  1642. {
  1643. RegCloseKey(SubKeyHandle);
  1644. }
  1645. ReleaseHttpRegistryMutex(IP_REGISTRY_KEY_SYNCHRONIZE);
  1646. // tell caller how many bytes are need
  1647. *pReturnLength = BytesNeeded;
  1648. }
  1649. return Status;
  1650. }
  1651. //
  1652. // URL ACL functions.
  1653. //
  1654. /***************************************************************************++
  1655. Routine Description:
  1656. Internal function that adds an URL ACL entry
  1657. Arguments:
  1658. pConfigInformation - pointer to HTTP_SERVICE_CONFIG_URL_ACL
  1659. ConfigInformationLength - length of input buffer.
  1660. Return Value:
  1661. Win32 error code.
  1662. --***************************************************************************/
  1663. ULONG
  1664. SetUrlAclInfo(
  1665. IN PVOID pConfigInformation,
  1666. IN ULONG ConfigInformationLength
  1667. )
  1668. {
  1669. DWORD Status;
  1670. PHTTP_SERVICE_CONFIG_URLACL_SET pUrlAcl;
  1671. PSECURITY_DESCRIPTOR pSecurityDescriptor;
  1672. ULONG SecurityDescriptorLength;
  1673. //
  1674. // Validate arguments.
  1675. //
  1676. if (pConfigInformation == NULL ||
  1677. ConfigInformationLength != sizeof(HTTP_SERVICE_CONFIG_URLACL_SET))
  1678. {
  1679. return ERROR_INVALID_PARAMETER;
  1680. }
  1681. pUrlAcl = (PHTTP_SERVICE_CONFIG_URLACL_SET) pConfigInformation;
  1682. if(FALSE == ConvertStringSecurityDescriptorToSecurityDescriptor(
  1683. pUrlAcl->ParamDesc.pStringSecurityDescriptor,
  1684. SDDL_REVISION_1,
  1685. &pSecurityDescriptor,
  1686. &SecurityDescriptorLength
  1687. ))
  1688. {
  1689. return GetLastError();
  1690. }
  1691. //
  1692. // Now, make the IOCTL call
  1693. //
  1694. Status = AddUrlToConfigGroup(
  1695. HttpUrlOperatorTypeReservation,
  1696. g_ServiceControlChannelHandle,
  1697. HTTP_NULL_ID,
  1698. pUrlAcl->KeyDesc.pUrlPrefix,
  1699. HTTP_NULL_ID,
  1700. pSecurityDescriptor,
  1701. SecurityDescriptorLength
  1702. );
  1703. LocalFree(pSecurityDescriptor);
  1704. return Status;
  1705. }
  1706. /***************************************************************************++
  1707. Routine Description:
  1708. Internal function that queries URL ACL configuration
  1709. Arguments:
  1710. pInputConfigInfo - pointer to HTTP_SERVICE_CONFIG_URLACL_QUERY
  1711. InputLength - length of input buffer.
  1712. pBuffer - Output Buffer
  1713. pReturnLength - Bytes written/needed.
  1714. BytesAvailable - sizeof output buffer
  1715. Return Value:
  1716. Win32 error code.
  1717. --***************************************************************************/
  1718. ULONG
  1719. QueryUrlAclInfo(
  1720. IN PVOID pInputConfigInfo,
  1721. IN ULONG InputLength,
  1722. IN PVOID pOutput,
  1723. IN ULONG OutputLength,
  1724. OUT PULONG pReturnLength
  1725. )
  1726. {
  1727. ULONG Status;
  1728. PHTTP_SERVICE_CONFIG_URLACL_QUERY pUrlAclQuery;
  1729. PHTTP_SERVICE_CONFIG_URLACL_SET pUrlAclSet;
  1730. DWORD dwIndex;
  1731. PVOID pData;
  1732. PUCHAR pBuffer;
  1733. DWORD Type;
  1734. DWORD DataSize;
  1735. DWORD NameSize;
  1736. PWSTR pFullyQualifiedUrl = NULL;
  1737. PSECURITY_DESCRIPTOR pSecurityDescriptor;
  1738. PWSTR pStringSecurityDescriptor;
  1739. BOOLEAN bAllocatedUrl = FALSE;
  1740. pData = NULL;
  1741. pStringSecurityDescriptor = NULL;
  1742. Status = NO_ERROR;
  1743. pUrlAclQuery = (PHTTP_SERVICE_CONFIG_URLACL_QUERY) pInputConfigInfo;
  1744. //
  1745. // Validate input parameters.
  1746. //
  1747. if(pUrlAclQuery == NULL ||
  1748. InputLength != sizeof(HTTP_SERVICE_CONFIG_URLACL_QUERY))
  1749. {
  1750. return ERROR_INVALID_PARAMETER;
  1751. }
  1752. switch(pUrlAclQuery->QueryDesc)
  1753. {
  1754. case HttpServiceConfigQueryNext:
  1755. {
  1756. dwIndex = pUrlAclQuery->dwToken;
  1757. DataSize = 0;
  1758. //
  1759. // RegEnumValue wants ValueName to be MAXUSHORT characters.
  1760. //
  1761. NameSize = (MAXUSHORT + 1) * sizeof(WCHAR);
  1762. pFullyQualifiedUrl = LocalAlloc(LMEM_FIXED, NameSize);
  1763. if(!pFullyQualifiedUrl)
  1764. {
  1765. return ERROR_NOT_ENOUGH_MEMORY;
  1766. }
  1767. else
  1768. {
  1769. RtlZeroMemory(pFullyQualifiedUrl, NameSize);
  1770. bAllocatedUrl = TRUE;
  1771. }
  1772. //
  1773. // Set NameSize to WCHARs & exclude the NULL.
  1774. //
  1775. NameSize = MAXUSHORT;
  1776. //
  1777. // Get the Size.
  1778. //
  1779. Status = RegEnumValue(
  1780. g_UrlAclRegistryHandle,
  1781. dwIndex,
  1782. pFullyQualifiedUrl,
  1783. &NameSize,
  1784. NULL, // Reserved
  1785. &Type, // Type
  1786. NULL, // Data
  1787. &DataSize // DataSize
  1788. );
  1789. // On return, NameSize contains size in WCHARs
  1790. // excluding NULL. Account for the NULL. The buffer is already
  1791. // zero'd out.
  1792. //
  1793. // At this time, NameSize is in WCHARs, including NULL
  1794. //
  1795. NameSize ++;
  1796. }
  1797. break;
  1798. case HttpServiceConfigQueryExact:
  1799. {
  1800. pFullyQualifiedUrl = pUrlAclQuery->KeyDesc.pUrlPrefix,
  1801. //
  1802. // NameSize must be in WCHARs including NULL.
  1803. //
  1804. NameSize = (DWORD)((wcslen(pFullyQualifiedUrl) + 1));
  1805. Status = RegQueryValueEx(
  1806. g_UrlAclRegistryHandle,
  1807. pFullyQualifiedUrl,
  1808. 0,
  1809. &Type,
  1810. NULL, // Buffer
  1811. &DataSize
  1812. );
  1813. }
  1814. break;
  1815. default:
  1816. Status = ERROR_INVALID_PARAMETER;
  1817. goto Cleanup;
  1818. } // switch
  1819. if(Status != NO_ERROR)
  1820. {
  1821. goto Cleanup;
  1822. }
  1823. if(Type != REG_BINARY || DataSize == 0)
  1824. {
  1825. Status = ERROR_REGISTRY_CORRUPT;
  1826. goto Cleanup;
  1827. }
  1828. //
  1829. // Allocate space for data
  1830. //
  1831. pData = LocalAlloc(LMEM_FIXED, DataSize);
  1832. if(!pData)
  1833. {
  1834. Status = ERROR_NOT_ENOUGH_MEMORY;
  1835. goto Cleanup;
  1836. }
  1837. Status = RegQueryValueEx(
  1838. g_UrlAclRegistryHandle,
  1839. pFullyQualifiedUrl,
  1840. 0,
  1841. &Type,
  1842. pData, // Buffer
  1843. &DataSize
  1844. );
  1845. if(Status != NO_ERROR)
  1846. {
  1847. goto Cleanup;
  1848. }
  1849. if(Type != REG_BINARY)
  1850. {
  1851. Status = ERROR_REGISTRY_CORRUPT;
  1852. goto Cleanup;
  1853. }
  1854. pSecurityDescriptor = (PSECURITY_DESCRIPTOR) pData;
  1855. //
  1856. // If we are here, we have to convert the binary to a SDDL.
  1857. //
  1858. if(FALSE == ConvertSecurityDescriptorToStringSecurityDescriptor(
  1859. pSecurityDescriptor,
  1860. SDDL_REVISION_1,
  1861. OWNER_SECURITY_INFORMATION |
  1862. GROUP_SECURITY_INFORMATION |
  1863. DACL_SECURITY_INFORMATION |
  1864. SACL_SECURITY_INFORMATION,
  1865. &pStringSecurityDescriptor,
  1866. &DataSize
  1867. ))
  1868. {
  1869. Status = GetLastError();
  1870. goto Cleanup;
  1871. }
  1872. //
  1873. // Convert WCHAR to length.
  1874. //
  1875. DataSize *= sizeof(WCHAR);
  1876. NameSize *= sizeof(WCHAR);
  1877. *pReturnLength = DataSize +
  1878. NameSize +
  1879. sizeof(HTTP_SERVICE_CONFIG_URLACL_SET);
  1880. if(OutputLength >= *pReturnLength)
  1881. {
  1882. pBuffer = pOutput;
  1883. pUrlAclSet = (PHTTP_SERVICE_CONFIG_URLACL_SET) pBuffer;
  1884. pBuffer += sizeof(HTTP_SERVICE_CONFIG_URLACL_SET);
  1885. RtlZeroMemory(pUrlAclSet, sizeof(HTTP_SERVICE_CONFIG_URLACL_SET));
  1886. pUrlAclSet->KeyDesc.pUrlPrefix = (PWSTR) pBuffer;
  1887. pBuffer += NameSize;
  1888. // Includes NULL.
  1889. RtlCopyMemory(
  1890. pUrlAclSet->KeyDesc.pUrlPrefix,
  1891. pFullyQualifiedUrl,
  1892. NameSize
  1893. );
  1894. pUrlAclSet->ParamDesc.pStringSecurityDescriptor = (PWSTR)pBuffer;
  1895. RtlCopyMemory(
  1896. pUrlAclSet->ParamDesc.pStringSecurityDescriptor,
  1897. pStringSecurityDescriptor,
  1898. DataSize
  1899. );
  1900. Status = NO_ERROR;
  1901. }
  1902. else
  1903. {
  1904. Status = ERROR_INSUFFICIENT_BUFFER;
  1905. }
  1906. Cleanup:
  1907. if(bAllocatedUrl)
  1908. {
  1909. LocalFree(pFullyQualifiedUrl);
  1910. }
  1911. if(pStringSecurityDescriptor)
  1912. {
  1913. LocalFree(pStringSecurityDescriptor);
  1914. }
  1915. if(pData)
  1916. {
  1917. LocalFree(pData);
  1918. }
  1919. return Status;
  1920. }
  1921. /***************************************************************************++
  1922. Routine Description:
  1923. Internal function that deletes an URL ACL entry
  1924. Arguments:
  1925. pConfigInformation - pointer to HTTP_SERVICE_CONFIG_URL_ACL
  1926. ConfigInformationLength - length of input buffer.
  1927. Return Value:
  1928. Win32 error code.
  1929. --***************************************************************************/
  1930. ULONG
  1931. DeleteUrlAclInfo(
  1932. IN PVOID pConfigInformation,
  1933. IN ULONG ConfigInformationLength
  1934. )
  1935. {
  1936. DWORD Status;
  1937. PHTTP_SERVICE_CONFIG_URLACL_SET pUrlAcl;
  1938. //
  1939. // Validate arguments.
  1940. //
  1941. if (pConfigInformation == NULL ||
  1942. ConfigInformationLength != sizeof(HTTP_SERVICE_CONFIG_URLACL_SET))
  1943. {
  1944. return ERROR_INVALID_PARAMETER;
  1945. }
  1946. pUrlAcl = (PHTTP_SERVICE_CONFIG_URLACL_SET) pConfigInformation;
  1947. //
  1948. // Now, make the IOCTL call
  1949. //
  1950. Status = RemoveUrlFromConfigGroup(
  1951. HttpUrlOperatorTypeReservation,
  1952. g_ServiceControlChannelHandle,
  1953. HTTP_NULL_ID,
  1954. pUrlAcl->KeyDesc.pUrlPrefix
  1955. );
  1956. return Status;
  1957. }
  1958. //
  1959. // Public Functions.
  1960. //
  1961. /***************************************************************************++
  1962. Routine Description:
  1963. Sets a service configuration parameter.
  1964. Arguments:
  1965. ConfigId - ID of the parameter that we are setting.
  1966. pConfigInformation - pointer to the object that is being set.
  1967. ConfigInformationLength - Length of the object.
  1968. Return Value:
  1969. ULONG - Completion status.
  1970. --***************************************************************************/
  1971. ULONG
  1972. WINAPI
  1973. HttpSetServiceConfiguration(
  1974. IN HANDLE pHandle,
  1975. IN HTTP_SERVICE_CONFIG_ID ConfigId,
  1976. IN PVOID pConfigInformation,
  1977. IN ULONG ConfigInformationLength,
  1978. IN LPOVERLAPPED pOverlapped
  1979. )
  1980. {
  1981. ULONG Status = NO_ERROR;
  1982. if(pOverlapped != NULL || pHandle != NULL)
  1983. {
  1984. return ERROR_INVALID_PARAMETER;
  1985. }
  1986. switch(ConfigId)
  1987. {
  1988. case HttpServiceConfigSSLCertInfo:
  1989. {
  1990. Status = SetSslServiceConfiguration(pConfigInformation,
  1991. ConfigInformationLength
  1992. );
  1993. break;
  1994. }
  1995. case HttpServiceConfigIPListenList:
  1996. {
  1997. Status = SetIpListenServiceConfiguration(
  1998. pConfigInformation,
  1999. ConfigInformationLength
  2000. );
  2001. break;
  2002. }
  2003. case HttpServiceConfigUrlAclInfo:
  2004. {
  2005. Status = SetUrlAclInfo(
  2006. pConfigInformation,
  2007. ConfigInformationLength
  2008. );
  2009. break;
  2010. }
  2011. default:
  2012. Status = ERROR_INVALID_PARAMETER;
  2013. break;
  2014. }
  2015. return Status;
  2016. }
  2017. /***************************************************************************++
  2018. Routine Description:
  2019. Deletes a service configuration parameter.
  2020. Arguments:
  2021. ConfigId - ID of the parameter that we are setting.
  2022. pConfigInformation - pointer to the object that is being set.
  2023. ConfigInformationLength - Length of the object.
  2024. Return Value:
  2025. ULONG - Completion status.
  2026. --***************************************************************************/
  2027. ULONG
  2028. WINAPI
  2029. HttpDeleteServiceConfiguration(
  2030. IN HANDLE pHandle,
  2031. IN HTTP_SERVICE_CONFIG_ID ConfigId,
  2032. IN PVOID pConfigInformation,
  2033. IN ULONG ConfigInformationLength,
  2034. IN LPOVERLAPPED pOverlapped
  2035. )
  2036. {
  2037. ULONG Status = NO_ERROR;
  2038. if(pOverlapped != NULL || pHandle != NULL)
  2039. {
  2040. return ERROR_INVALID_PARAMETER;
  2041. }
  2042. switch(ConfigId)
  2043. {
  2044. case HttpServiceConfigSSLCertInfo:
  2045. Status = DeleteSslServiceConfiguration(pConfigInformation,
  2046. ConfigInformationLength
  2047. );
  2048. break;
  2049. case HttpServiceConfigIPListenList:
  2050. {
  2051. Status = DeleteIpListenServiceConfiguration(
  2052. pConfigInformation,
  2053. ConfigInformationLength
  2054. );
  2055. break;
  2056. }
  2057. case HttpServiceConfigUrlAclInfo:
  2058. {
  2059. Status = DeleteUrlAclInfo(
  2060. pConfigInformation,
  2061. ConfigInformationLength
  2062. );
  2063. break;
  2064. }
  2065. default:
  2066. Status = ERROR_INVALID_PARAMETER;
  2067. break;
  2068. }
  2069. return Status;
  2070. }
  2071. /***************************************************************************++
  2072. Routine Description:
  2073. Queries a service configuration parameter.
  2074. Arguments:
  2075. ConfigId - ID of the parameter that we are setting.
  2076. pConfigInformation - pointer to the object that is being set.
  2077. ConfigInformationLength - Length of the object.
  2078. Return Value:
  2079. ULONG - Completion status.
  2080. --***************************************************************************/
  2081. ULONG
  2082. WINAPI
  2083. HttpQueryServiceConfiguration(
  2084. IN HANDLE pHandle,
  2085. IN HTTP_SERVICE_CONFIG_ID ConfigId,
  2086. IN PVOID pInput,
  2087. IN ULONG InputLength,
  2088. IN OUT PVOID pOutput,
  2089. IN ULONG OutputLength,
  2090. OUT PULONG pReturnLength,
  2091. IN LPOVERLAPPED pOverlapped
  2092. )
  2093. {
  2094. ULONG Status = NO_ERROR;
  2095. if(pOverlapped != NULL || pHandle != NULL)
  2096. {
  2097. return ERROR_INVALID_PARAMETER;
  2098. }
  2099. switch(ConfigId)
  2100. {
  2101. case HttpServiceConfigSSLCertInfo:
  2102. {
  2103. Status = QuerySslServiceConfiguration(
  2104. pInput,
  2105. InputLength,
  2106. pOutput,
  2107. OutputLength,
  2108. pReturnLength
  2109. );
  2110. break;
  2111. }
  2112. case HttpServiceConfigIPListenList:
  2113. {
  2114. Status = QueryIpListenServiceConfiguration(
  2115. pOutput,
  2116. OutputLength,
  2117. pReturnLength
  2118. );
  2119. break;
  2120. }
  2121. case HttpServiceConfigUrlAclInfo:
  2122. {
  2123. Status = QueryUrlAclInfo(
  2124. pInput,
  2125. InputLength,
  2126. pOutput,
  2127. OutputLength,
  2128. pReturnLength
  2129. );
  2130. break;
  2131. }
  2132. default:
  2133. Status = ERROR_INVALID_PARAMETER;
  2134. break;
  2135. }
  2136. return Status;
  2137. }