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

1682 lines
38 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. Terminal Server ISAPI Proxy
  5. Abstract:
  6. This is the ISAPI side of the terminal server proxy. This opens a connection to the
  7. proxied server and then forwards data back and forth through IIS. There is also
  8. a filter component which takes care of having more user friendly urls.
  9. Author:
  10. Marc Reyhner 8/22/2000
  11. --*/
  12. #include "stdafx.h"
  13. #include <atlbase.h>
  14. #include <atlconv.h>
  15. #include "tsproxy.h"
  16. #include "tsproxyacl.h"
  17. //
  18. // Disable tracing for free builds.
  19. //
  20. #if DBG
  21. #ifndef TRC_CL
  22. #define TRC_CL TRC_LEVEL_DBG
  23. #endif
  24. #define TRC_ENABLE_PRF
  25. #else
  26. #ifndef TRC_CL
  27. #define TRC_CL TRC_LEVEL_DIS
  28. #endif
  29. #undef TRC_ENABLE_PRF
  30. #endif
  31. //
  32. // Required for DCL Tracing
  33. //
  34. #define TRC_FILE "tsproxy"
  35. #ifndef OS_WIN32
  36. #define OS_WIN32
  37. #endif
  38. #define TRC_GROUP TRC_GROUP_NETWORK
  39. #define DEBUG_MODULE DBG_MOD_ANY
  40. #include <adcgbase.h>
  41. #include <at120ex.h>
  42. #include <atrcapi.h>
  43. #include <adcgbase.h>
  44. #include <at120ex.h>
  45. HINSTANCE g_hInstance;
  46. //macros for goto end
  47. #define CFRg(x) { if(!x) goto END; }
  48. // The name the DLL returns to IIS.
  49. #define ISAPI_DLL_NAME "Microsoft Terminal Server Proxy"
  50. // The amount of data we read or send at once. This is set to the
  51. // maximum amount before a SSL encrypt/decrypt needs to be chunked
  52. #define TS_PROXY_READ_SIZE 16379
  53. #define TS_MAX_READ_SIZE 200
  54. // Various HTTP defines
  55. #define HTTP_STATUS_OK "200 OK"
  56. #define HTTP_STATUS_ERR "502 Terminal Server Proxy Connect Failure"
  57. #define HTTP_METHOD_HEAD "HEAD"
  58. #define HTTP_CONTENTLENGTH_ZERO "Content-Length: 0\r\n"
  59. #define HTTP_USER_AGENT "HTTP_USER_AGENT:"
  60. #define TS_USER_AGENT_PREFIX "Microsoft Terminal Server Proxy"
  61. #define HTTP_URL_PREFIX "http://"
  62. #define HTTPS_URL_PREFIX "https://"
  63. // Settings that can be changed in the registry
  64. // _NAME is the name of the value in the registry
  65. // _DFLT is the default value.
  66. #define TS_PROXY_REMAP_PREFIX_NAME "Url Remap Prefix"
  67. #define TS_PROXY_REMAP_PREFIX_DFLT "/ts"
  68. #define TS_PROXY_REMAP_DEST_URL_NAME "Url Remap Destination"
  69. #define TS_PROXY_REMAP_DEST_URL_DFLT "/tsproxy/connect.asp"
  70. // not configurable but placed here since it belongs with the previous setting.
  71. #define TS_PROXY_REMAP_DEST_URL_SUFFIX "%s?Server=%s&ProxyServer=%s"
  72. #define TS_PROXY_INC_AGENT_DEST_NAME "Invalid User Agent Redirect"
  73. #define TS_PROXY_INC_AGENT_DEST_DFLT "/browser.htm"
  74. #define TS_PROXY_CONNECT_PORT_NAME "Terminal Server Port"
  75. #define TS_PROXY_CONNECT_PORT_DFLT 0xD3D
  76. #define TS_PROXY_WSSNDBUFSIZE 4096
  77. #define TS_PROXY_WSRCVBUFSIZE 8192
  78. // Various Structures
  79. typedef struct _READCALLBACKCONTEXT
  80. {
  81. HANDLE serverListenThread;
  82. SOCKET s;
  83. DWORD cbReadSoFar; // Number of bytes read so far, used as index for readBuffer
  84. CHAR readBuffer[ TS_MAX_READ_SIZE ];
  85. LPEXTENSION_CONTROL_BLOCK lpECB;
  86. } READCALLBACKCONTEXT, FAR *LPREADCALLBACKCONTEXT;
  87. typedef struct _SERVERLISTENTCONTEXT
  88. {
  89. BOOL bTerminate;
  90. SOCKET s;
  91. LPEXTENSION_CONTROL_BLOCK lpECB;
  92. } SERVERLISTENTCONTEXT, FAR *LPSERVERLISTENTCONTEXT;
  93. // Static internal functions
  94. static BOOL VerifyTsacUserAgent(LPEXTENSION_CONTROL_BLOCK lpECB);
  95. static DWORD RedirectToBrowserPage(LPEXTENSION_CONTROL_BLOCK lpECB);
  96. static LPSTR GetAndAllocateExtensionServerVariable(LPEXTENSION_CONTROL_BLOCK lpECB,
  97. LPSTR lpstrVariable);
  98. static LPSTR GetAndAllocateFilterServerVariable(PHTTP_FILTER_CONTEXT pfc,
  99. LPSTR lpstrVariable);
  100. static LPSTR GetAndAllocateFilterHeader(PHTTP_FILTER_CONTEXT pfc,
  101. PHTTP_FILTER_PREPROC_HEADERS pPreproc,
  102. LPSTR lpstrVariable);
  103. static DWORD StartTsProxy(LPEXTENSION_CONTROL_BLOCK lpECB);
  104. static DWORD WINAPI ServerListenThread(LPVOID lpParameter);
  105. VOID WINAPI ProxyReadCallback(LPEXTENSION_CONTROL_BLOCK lpECB,
  106. PVOID pContext,DWORD cbIO,DWORD dwError);
  107. static DWORD GetRegValueAsDword(LPCSTR regValue, DWORD dwDefaultValue);
  108. static DWORD ReadFromClient(LPVOID lpParameter );
  109. static LPSTR GetRegValueAsAnsiString(LPCSTR regValue, LPSTR defaultValue);
  110. static LPVOID QueryRegistryData(LPCSTR regValue, DWORD typeRequested);
  111. BOOL APIENTRY
  112. DllMain(
  113. IN HINSTANCE hModule,
  114. IN DWORD ul_reason_for_call,
  115. IN LPVOID lpReserved
  116. )
  117. /*++
  118. Routine Description:
  119. With DllMain we start winsock on process attach and stop it when
  120. we are detached from the process.
  121. Arguments:
  122. hModule - Instance for this dll
  123. ul_reason_for_call - Why we were called.
  124. lpReserved - Reserved parameter. Should be Null?
  125. Return Value:
  126. TRUE - Loading the dll was successfull
  127. FALSE - There was an error loading the dll.
  128. --*/
  129. {
  130. WORD wSockVersion;
  131. INT result;
  132. WSADATA wsaData;
  133. BOOL retValue;
  134. DC_BEGIN_FN("DllMain");
  135. retValue = TRUE;
  136. switch (ul_reason_for_call)
  137. {
  138. case DLL_PROCESS_ATTACH:
  139. g_hInstance = hModule;
  140. wSockVersion = MAKEWORD(2,0);
  141. result = WSAStartup(wSockVersion,&wsaData);
  142. if (result)
  143. {
  144. retValue = FALSE;
  145. }
  146. break;
  147. case DLL_PROCESS_DETACH:
  148. WSACleanup();
  149. break;
  150. }
  151. DC_END_FN();
  152. return retValue;
  153. }
  154. BOOL WINAPI
  155. GetFilterVersion(
  156. IN PHTTP_FILTER_VERSION pVer
  157. )
  158. /*++
  159. Routine Description:
  160. Here we registers ourselves to get preproc header notifications and set
  161. the version of IIS we were compiled against.
  162. Arguments:
  163. pVer - Filter version struct we need to fill in.
  164. Return Value:
  165. TRUE - We don't have any way to cause an error so we always return true.
  166. --*/
  167. {
  168. DC_BEGIN_FN("GetFilterVersion");
  169. pVer->dwFlags = ( SF_NOTIFY_PREPROC_HEADERS|SF_NOTIFY_ORDER_DEFAULT);
  170. pVer->dwFilterVersion = HTTP_FILTER_REVISION;
  171. strncpy( pVer->lpszFilterDesc,ISAPI_DLL_NAME,SF_MAX_FILTER_DESC_LEN-1);
  172. DC_END_FN();
  173. return TRUE;
  174. }
  175. DWORD WINAPI
  176. HttpFilterProc(
  177. IN PHTTP_FILTER_CONTEXT pfc,
  178. IN DWORD notificationType,
  179. IN LPVOID pvNotification
  180. )
  181. /*++
  182. Routine Description:
  183. If the client requests a url that begins with our url base. We remap
  184. it to the page which hosts the tsac control and fill in the server and
  185. proxy server settings. For example by default. /ts/devmachine would be
  186. remapped to /tsproxy/connect.asp?Server=devmachine?ProxyServer=SERVER_NAME
  187. where SERVER_NAME is the name of the server as fetched from IIS.
  188. Arguments:
  189. pfc - Filter context passed in.
  190. notificationType - Always SF_NOTIFY_PREPROC_HEADERS since that is the only
  191. event we are registered for.
  192. pvNotification - A PHTTP_FILTER_PREPROC_HEADERS structure passed in by IIS.
  193. Return Value:
  194. SF_STATUS_REQ_NEXT_NOTIFICATION - We always return that IIS should go on
  195. to the next filter.
  196. --*/
  197. {
  198. PHTTP_FILTER_PREPROC_HEADERS preproc;
  199. DWORD dwNewUrlSize;
  200. LPSTR origUrl = NULL ;
  201. LPSTR serverName, chunked, clen;
  202. LPSTR newUrl = NULL;
  203. LPSTR remapPrefix = NULL;
  204. LPSTR newUrlBase = NULL;
  205. LPCSTR host;
  206. DWORD dwRemapPrefixLength;
  207. serverName = NULL;
  208. DC_BEGIN_FN("HttpFilterProc");
  209. preproc = (PHTTP_FILTER_PREPROC_HEADERS)pvNotification;
  210. origUrl = GetAndAllocateFilterHeader(pfc,preproc,"URL");
  211. if (!origUrl)
  212. {
  213. goto EXIT_POINT;
  214. }
  215. remapPrefix = GetRegValueAsAnsiString( TS_PROXY_REMAP_PREFIX_NAME, TS_PROXY_REMAP_PREFIX_DFLT );
  216. if (!remapPrefix)
  217. {
  218. goto EXIT_POINT;
  219. }
  220. dwRemapPrefixLength = strlen(remapPrefix);
  221. if (0 != strncmp(origUrl,remapPrefix,dwRemapPrefixLength))
  222. {
  223. goto EXIT_POINT;
  224. }
  225. if (remapPrefix[dwRemapPrefixLength-1] != '/')
  226. {
  227. if (origUrl[dwRemapPrefixLength] != '/')
  228. {
  229. goto EXIT_POINT;
  230. }
  231. dwRemapPrefixLength++;
  232. }
  233. host = origUrl + dwRemapPrefixLength;
  234. serverName = GetAndAllocateFilterServerVariable(pfc,"SERVER_NAME");
  235. if (!serverName)
  236. {
  237. goto EXIT_POINT;
  238. }
  239. chunked = GetAndAllocateFilterServerVariable(pfc,"HTTP_TRANSFER_ENCODING");
  240. clen = GetAndAllocateFilterServerVariable(pfc,"CONTENT_LENGTH");
  241. newUrlBase = GetRegValueAsAnsiString( TS_PROXY_REMAP_DEST_URL_NAME, TS_PROXY_REMAP_DEST_URL_DFLT );
  242. if (!newUrlBase)
  243. {
  244. goto EXIT_POINT;
  245. }
  246. dwNewUrlSize = strlen(newUrlBase) + strlen(TS_PROXY_REMAP_DEST_URL_SUFFIX)
  247. - 6 + strlen(host) + strlen(serverName) + 1;
  248. newUrl = (LPSTR)HeapAlloc(GetProcessHeap(),0,dwNewUrlSize);
  249. if (!newUrl)
  250. {
  251. goto EXIT_POINT;
  252. }
  253. wsprintfA(newUrl,TS_PROXY_REMAP_DEST_URL_SUFFIX,newUrlBase,host,serverName);
  254. preproc->SetHeader(pfc,"URL",newUrl);
  255. EXIT_POINT:
  256. if (origUrl)
  257. {
  258. HeapFree(GetProcessHeap(),0,origUrl);
  259. }
  260. if (serverName)
  261. {
  262. HeapFree(GetProcessHeap(),0,serverName);
  263. }
  264. if (newUrl)
  265. {
  266. HeapFree(GetProcessHeap(),0,newUrl);
  267. }
  268. if (remapPrefix)
  269. {
  270. HeapFree(GetProcessHeap(),0,remapPrefix);
  271. }
  272. if (newUrlBase)
  273. {
  274. HeapFree(GetProcessHeap(),0,newUrlBase);
  275. }
  276. DC_END_FN();
  277. return SF_STATUS_REQ_NEXT_NOTIFICATION;
  278. }
  279. BOOL WINAPI
  280. GetExtensionVersion(
  281. IN HSE_VERSION_INFO* pVer
  282. )
  283. /*++
  284. Routine Description:
  285. We simple set our name and the version of IIS we were compiled against.
  286. Arguments:
  287. pVer - Extension version struct we need to fill in.
  288. Return Value:
  289. TRUE - We don't have any way to cause an error so we always return true.
  290. --*/
  291. {
  292. DC_BEGIN_FN("GetExtensionVersion");
  293. pVer->dwExtensionVersion = HSE_VERSION;
  294. strncpy(pVer->lpszExtensionDesc,ISAPI_DLL_NAME,HSE_MAX_EXT_DLL_NAME_LEN-1);
  295. DC_END_FN();
  296. return TRUE;
  297. }
  298. DWORD WINAPI
  299. HttpExtensionProc(
  300. IN LPEXTENSION_CONTROL_BLOCK lpECB
  301. )
  302. /*++
  303. Routine Description:
  304. This is the primary entry point for the dll. IIS calls this function
  305. whenever there is a connection for our extension. We first check to
  306. see if the user agent is the terminal server client. If not we send a 302
  307. response to the client to a url which tells them they can't use this url
  308. with a browser. If it is the terminal server client we attempt to open
  309. a tcp connection to the server they specify in the query string and then
  310. start routing data back and forth.
  311. Arguments:
  312. lpECB - Extension control block structure passed in from IIS.
  313. Return Value:
  314. HSE_STATUS_PENDING - We still have more processing to do.
  315. HSE_STATUS_ERROR - There was an error while processing the connection.
  316. HSE_STATUS_SUCCESS_AND_KEEP_CONN - The extension is done and IIS should
  317. keep the connection open.
  318. --*/
  319. {
  320. DWORD dwRetCode;
  321. HSE_SEND_HEADER_EX_INFO headerEx;
  322. BOOL result;
  323. DC_BEGIN_FN("HttpExtensionProc");
  324. if (!VerifyTsacUserAgent(lpECB))
  325. {
  326. DC_END_FN();
  327. return RedirectToBrowserPage(lpECB);
  328. }
  329. if (0 == strcmp(lpECB->lpszMethod,HTTP_METHOD_HEAD))
  330. {
  331. headerEx.pszStatus = HTTP_STATUS_OK;
  332. headerEx.cchStatus = strlen(HTTP_STATUS_OK);
  333. headerEx.pszHeader = HTTP_CONTENTLENGTH_ZERO;
  334. headerEx.cchHeader = strlen(HTTP_CONTENTLENGTH_ZERO);
  335. headerEx.fKeepConn = TRUE;
  336. result = lpECB->ServerSupportFunction(lpECB->ConnID,
  337. HSE_REQ_SEND_RESPONSE_HEADER_EX,&headerEx,NULL,NULL);
  338. if (result)
  339. {
  340. DC_END_FN();
  341. return HSE_STATUS_SUCCESS_AND_KEEP_CONN;
  342. }
  343. else
  344. {
  345. DC_END_FN();
  346. return HSE_STATUS_ERROR;
  347. }
  348. }
  349. else
  350. {
  351. dwRetCode = StartTsProxy(lpECB);
  352. if (dwRetCode != HSE_STATUS_ERROR)
  353. {
  354. headerEx.pszStatus = HTTP_STATUS_OK;
  355. headerEx.cchStatus = strlen(HTTP_STATUS_OK);
  356. }
  357. else
  358. {
  359. headerEx.pszStatus = HTTP_STATUS_ERR;
  360. headerEx.cchStatus = strlen(HTTP_STATUS_ERR);
  361. }
  362. headerEx.pszHeader = NULL;
  363. headerEx.cchHeader = 0;
  364. headerEx.fKeepConn = TRUE;
  365. lpECB->ServerSupportFunction(lpECB->ConnID,
  366. HSE_REQ_SEND_RESPONSE_HEADER_EX,&headerEx,NULL,NULL);
  367. DC_END_FN();
  368. return dwRetCode;
  369. }
  370. }
  371. BOOL WINAPI
  372. TerminateExtension(
  373. IN DWORD dwFlags
  374. )
  375. /*++
  376. Routine Description:
  377. IIS calls this when we are about to be unloaded. Currently
  378. we don't do any processing here because IIS will not call us
  379. when we have open connections.
  380. Arguments:
  381. dwFlags - IIS flags on why this function has been called.
  382. Return Value:
  383. TRUE - We don't have any way to cause an error so we always return true.
  384. --*/
  385. {
  386. return TRUE;
  387. }
  388. BOOL
  389. VerifyTsacUserAgent(
  390. IN LPEXTENSION_CONTROL_BLOCK lpECB
  391. )
  392. /*++
  393. Routine Description:
  394. This checks to see if the client user agent matches
  395. that of the terminal server client.
  396. Arguments:
  397. lpECB - Extension control block given to use by IIS.
  398. Return Value:
  399. TRUE - The user agent string matches that of the terminal server client.
  400. FALSE - The user agent string doesn't match that of TSAC.
  401. --*/
  402. {
  403. LPSTR headers;
  404. LPSTR line;
  405. LPSTR lineEnd;
  406. LPSTR userAgent;
  407. BOOL succeeded;
  408. DC_BEGIN_FN("VerifyTsacUserAgent");
  409. succeeded = FALSE;
  410. headers = GetAndAllocateExtensionServerVariable(lpECB,"ALL_HTTP");
  411. if (!headers)
  412. {
  413. goto CLEANUP_AND_EXIT;
  414. }
  415. line = headers;
  416. // While strlen(line) > 0 is what we are doing here
  417. while (line[0] != '\0')
  418. {
  419. lineEnd = strchr(line,'\n');
  420. if (!lineEnd)
  421. {
  422. goto CLEANUP_AND_EXIT;
  423. }
  424. *lineEnd = '\0';
  425. if (0 == strncmp(HTTP_USER_AGENT,line,strlen(HTTP_USER_AGENT)))
  426. {
  427. userAgent = line + strlen(HTTP_USER_AGENT);
  428. if (0 == strncmp(userAgent,TS_USER_AGENT_PREFIX,
  429. strlen(TS_USER_AGENT_PREFIX)))
  430. {
  431. succeeded = TRUE;
  432. break;
  433. }
  434. }
  435. line += ((lineEnd - line) + 1);
  436. }
  437. CLEANUP_AND_EXIT:
  438. if (headers)
  439. {
  440. HeapFree(GetProcessHeap(),0,headers);
  441. }
  442. DC_END_FN();
  443. return succeeded;
  444. }
  445. DWORD
  446. RedirectToBrowserPage(
  447. IN LPEXTENSION_CONTROL_BLOCK lpECB
  448. )
  449. /*++
  450. Routine Description:
  451. This attempts to do a redirect to either the default browser
  452. page or the one defined in the registry.
  453. Arguments:
  454. lpECB - Extension control block structure passed in from IIS.
  455. Return Value:
  456. HSE_STATUS_ERROR - There was an error while processing the redirect.
  457. HSE_STATUS_SUCCESS_AND_KEEP_CONN - The redirect was succeeded and IIS should
  458. keep the connection open.
  459. --*/
  460. {
  461. LPSTR fullRedirectUrl;
  462. DWORD fullRedirectUrlLength;
  463. LPSTR serverName;
  464. LPSTR https;
  465. BOOL failure;
  466. BOOL result;
  467. LPSTR urlPrefix;
  468. LPSTR url;
  469. DC_BEGIN_FN("RedirectToBrowserPage");
  470. failure = FALSE;
  471. serverName = NULL;
  472. https = NULL;
  473. fullRedirectUrl = NULL;
  474. url = NULL;
  475. serverName = GetAndAllocateExtensionServerVariable(lpECB,"SERVER_NAME");
  476. if (!serverName)
  477. {
  478. failure = TRUE;
  479. goto CLEANUP_AND_EXIT;
  480. }
  481. https = GetAndAllocateExtensionServerVariable(lpECB,"HTTPS");
  482. if (!https)
  483. {
  484. failure = TRUE;
  485. goto CLEANUP_AND_EXIT;
  486. }
  487. if (0 == strcmp(https,"on"))
  488. {
  489. urlPrefix = HTTPS_URL_PREFIX;
  490. }
  491. else
  492. {
  493. urlPrefix = HTTP_URL_PREFIX;
  494. }
  495. url = GetRegValueAsAnsiString(TS_PROXY_INC_AGENT_DEST_NAME, TS_PROXY_INC_AGENT_DEST_DFLT);
  496. if (!url)
  497. {
  498. failure = TRUE;
  499. goto CLEANUP_AND_EXIT;
  500. }
  501. fullRedirectUrlLength = strlen(urlPrefix) + strlen(serverName) + strlen(url) + 1;
  502. fullRedirectUrl = (LPSTR)HeapAlloc(GetProcessHeap(), 0, fullRedirectUrlLength);
  503. if (!fullRedirectUrl)
  504. {
  505. failure = TRUE;
  506. goto CLEANUP_AND_EXIT;
  507. }
  508. strcpy(fullRedirectUrl,urlPrefix);
  509. strcat(fullRedirectUrl,serverName);
  510. strcat(fullRedirectUrl,url);
  511. result = lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_SEND_URL_REDIRECT_RESP,fullRedirectUrl,&fullRedirectUrlLength,NULL);
  512. if (!result)
  513. {
  514. failure = TRUE;
  515. goto CLEANUP_AND_EXIT;
  516. }
  517. CLEANUP_AND_EXIT:
  518. if (serverName)
  519. {
  520. HeapFree(GetProcessHeap(),0,serverName);
  521. }
  522. if (https)
  523. {
  524. HeapFree(GetProcessHeap(),0,https);
  525. }
  526. if (fullRedirectUrl)
  527. {
  528. HeapFree(GetProcessHeap(),0,fullRedirectUrl);
  529. }
  530. if (url)
  531. {
  532. HeapFree(GetProcessHeap(),0,url);
  533. }
  534. DC_END_FN();
  535. if (failure)
  536. {
  537. return HSE_STATUS_ERROR;
  538. }
  539. else
  540. {
  541. return HSE_STATUS_SUCCESS_AND_KEEP_CONN;
  542. }
  543. }
  544. LPSTR
  545. GetAndAllocateExtensionServerVariable(
  546. IN LPEXTENSION_CONTROL_BLOCK lpECB,
  547. IN LPSTR lpstrVariable
  548. )
  549. /*++
  550. Routine Description:
  551. This gets the requested extension server variable from IIS and allocates
  552. memory to hold the result.
  553. Arguments:
  554. lpECB - Extension control block structure passed in from IIS.
  555. lpstrVariable - Name of the variable that is being requested.
  556. Return Value:
  557. Non NULL - The value of the variable requested.
  558. NULL - There was an error getting the requested variable
  559. --*/
  560. {
  561. LPSTR value;
  562. DWORD valueLength;
  563. BOOL failure;
  564. BOOL result;
  565. DC_BEGIN_FN("GetAndAllocateExtensionServerVariable");
  566. failure = FALSE;
  567. value = NULL;
  568. valueLength = 0;
  569. result = lpECB->GetServerVariable(lpECB->ConnID,lpstrVariable,
  570. NULL,&valueLength);
  571. if (result || ERROR_INSUFFICIENT_BUFFER != GetLastError())
  572. {
  573. failure = TRUE;
  574. goto CLEANUP_AND_EXIT;
  575. }
  576. value = (LPSTR)HeapAlloc(GetProcessHeap(), 0, valueLength);
  577. if (!value)
  578. {
  579. failure = TRUE;
  580. goto CLEANUP_AND_EXIT;
  581. }
  582. result = lpECB->GetServerVariable(lpECB->ConnID,lpstrVariable,
  583. value,&valueLength);
  584. if (!result)
  585. {
  586. failure = TRUE;
  587. goto CLEANUP_AND_EXIT;
  588. }
  589. CLEANUP_AND_EXIT:
  590. if (failure)
  591. {
  592. if (value)
  593. {
  594. HeapFree(GetProcessHeap(),0,value);
  595. value = NULL;
  596. }
  597. }
  598. DC_END_FN();
  599. return value;
  600. }
  601. LPSTR
  602. GetAndAllocateFilterServerVariable(
  603. IN PHTTP_FILTER_CONTEXT pfc,
  604. IN LPSTR lpstrVariable
  605. )
  606. /*++
  607. Routine Description:
  608. This gets the requested filter server variable from IIS and allocates
  609. memory to hold the result.
  610. Arguments:
  611. pfc - Filter context for this session.
  612. lpstrVariable - Name of the variable that is being requested.
  613. Return Value:
  614. Non NULL - The value of the variable requested.
  615. NULL - There was an error getting the requested variable
  616. --*/
  617. {
  618. LPSTR value;
  619. DWORD valueLength;
  620. BOOL failure;
  621. BOOL result;
  622. DC_BEGIN_FN("GetAndAllocateFilterServerVariable");
  623. failure = FALSE;
  624. value = NULL;
  625. valueLength = 0;
  626. result = pfc->GetServerVariable(pfc,lpstrVariable,NULL,&valueLength);
  627. if (result || ERROR_INSUFFICIENT_BUFFER != GetLastError())
  628. {
  629. failure = TRUE;
  630. goto CLEANUP_AND_EXIT;
  631. }
  632. value = (LPSTR)HeapAlloc(GetProcessHeap(), 0, valueLength);
  633. if (!value)
  634. {
  635. failure = TRUE;
  636. goto CLEANUP_AND_EXIT;
  637. }
  638. result = pfc->GetServerVariable(pfc,lpstrVariable,value,&valueLength);
  639. if (!result)
  640. {
  641. failure = TRUE;
  642. goto CLEANUP_AND_EXIT;
  643. }
  644. CLEANUP_AND_EXIT:
  645. if (failure)
  646. {
  647. if (value)
  648. {
  649. HeapFree(GetProcessHeap(),0,value);
  650. value = NULL;
  651. }
  652. }
  653. DC_END_FN();
  654. return value;
  655. }
  656. LPSTR
  657. GetAndAllocateFilterHeader(
  658. IN PHTTP_FILTER_CONTEXT pfc,
  659. IN PHTTP_FILTER_PREPROC_HEADERS pPreproc,
  660. IN LPSTR lpstrVariable
  661. )
  662. /*++
  663. Routine Description:
  664. This gets the requested filter header from IIS and allocates
  665. memory to hold the result.
  666. Arguments:
  667. pfc - Filter context for this session.
  668. pPreproc - Preproc headers structure given by IIS.
  669. lpstrVariable - Name of the header that is being requested.
  670. Return Value:
  671. Non NULL - The value of the header requested.
  672. NULL - There was an error getting the requested header
  673. --*/
  674. {
  675. LPSTR value;
  676. DWORD valueLength;
  677. BOOL failure;
  678. BOOL result;
  679. DC_BEGIN_FN("GetAndAllocateFilterHeader");
  680. failure = FALSE;
  681. value = NULL;
  682. valueLength = 0;
  683. result = pPreproc->GetHeader(pfc,lpstrVariable,NULL,&valueLength);
  684. if (result || ERROR_INSUFFICIENT_BUFFER != GetLastError())
  685. {
  686. failure = TRUE;
  687. goto CLEANUP_AND_EXIT;
  688. }
  689. value = (LPSTR)HeapAlloc(GetProcessHeap(), 0, valueLength);
  690. if (!value)
  691. {
  692. failure = TRUE;
  693. goto CLEANUP_AND_EXIT;
  694. }
  695. result = pPreproc->GetHeader(pfc,lpstrVariable,value,&valueLength);
  696. if (!result)
  697. {
  698. failure = TRUE;
  699. goto CLEANUP_AND_EXIT;
  700. }
  701. CLEANUP_AND_EXIT:
  702. if (failure)
  703. {
  704. if (value)
  705. {
  706. HeapFree(GetProcessHeap(),0,value);
  707. value = NULL;
  708. }
  709. }
  710. DC_END_FN();
  711. return value;
  712. }
  713. DWORD
  714. StartTsProxy(
  715. IN LPEXTENSION_CONTROL_BLOCK lpECB
  716. )
  717. /*++
  718. Routine Description:
  719. This attempts to open a connection to the remote server. We then
  720. start the server listen thread and the client read async callback.
  721. If an error occurrs we close the server connection and tell
  722. IIS to give up.
  723. Arguments:
  724. lpECB - Extension control block for the session.
  725. Return Value:
  726. HSE_STATUS_PENDING - The proxy was started and IIS should wait for
  727. it to finish.
  728. HSE_STATUS_ERROR - There was an error starting the proxy.
  729. --*/
  730. {
  731. USES_CONVERSION;
  732. BOOL fSuccess = FALSE;
  733. struct hostent *host;
  734. struct sockaddr_in addr_in;
  735. SOCKET s;
  736. int status;
  737. BOOL optVal;
  738. LPREADCALLBACKCONTEXT lpReadContext;
  739. LPSERVERLISTENTCONTEXT lpServerContext;
  740. HANDLE serverThread;
  741. DWORD dwBufferSize;
  742. DWORD retValue;
  743. DWORD dwResult;
  744. DWORD dwConnectPort;
  745. LPSTR lpstrUsername;
  746. unsigned long nonBlocking = 0;
  747. DCINT sizeVal;
  748. HANDLE ClientThread;
  749. DC_BEGIN_FN("StartTsProxy");
  750. lpReadContext = NULL;
  751. lpServerContext = NULL;
  752. serverThread = NULL;
  753. s = INVALID_SOCKET;
  754. lpstrUsername = NULL;
  755. if (strlen(lpECB->lpszQueryString)==0)
  756. {
  757. // We didn't get a server to connect to.
  758. DC_QUIT;
  759. }
  760. host = gethostbyname(lpECB->lpszQueryString);
  761. if (!host)
  762. {
  763. // DNS lookup on the hostname failed
  764. DC_QUIT;
  765. }
  766. lpstrUsername = GetAndAllocateExtensionServerVariable(lpECB,"LOGON_USER");
  767. if (!VerifyServerAccess(lpECB,host->h_name, lpstrUsername))
  768. {
  769. DC_QUIT;
  770. }
  771. s = socket(AF_INET, SOCK_STREAM, 0);
  772. if ( INVALID_SOCKET == s )
  773. {
  774. TRC_ERR((TB, _T("Failed to get a socket - GLE:%d"), WSAGetLastError()));
  775. DC_QUIT;
  776. }
  777. /************************************************************************/
  778. /* Set the required options on this socket. We do the following: */
  779. /* */
  780. /* - disable the NAGLE algorithm. */
  781. /* - enable the don't linger option. This means the closesocket call */
  782. /* will return immediately while any data queued for transmission */
  783. /* will be sent, if possible, before the underlying socket is */
  784. /* closed. */
  785. /************************************************************************/
  786. optVal = TRUE;
  787. status = setsockopt( s, IPPROTO_TCP, TCP_NODELAY, (PCHAR)&optVal, sizeof(optVal));
  788. status = setsockopt( s, SOL_SOCKET, SO_DONTLINGER,(PCHAR)&optVal, sizeof(optVal));
  789. //
  790. // Put the socket in blocking mode;
  791. //
  792. status = ioctlsocket( s, FIONBIO, &nonBlocking);
  793. ZeroMemory( &addr_in, sizeof( addr_in ));
  794. addr_in.sin_family = AF_INET;
  795. dwConnectPort = GetRegValueAsDword( TS_PROXY_CONNECT_PORT_NAME, TS_PROXY_CONNECT_PORT_DFLT );
  796. addr_in.sin_port = htons((USHORT)dwConnectPort);
  797. CopyMemory( &addr_in.sin_addr, host->h_addr_list[0], sizeof(addr_in.sin_addr) );
  798. status = connect( s, (struct sockaddr *)&addr_in, sizeof(addr_in) );
  799. /********************************************************************/
  800. /* We expect the connect to return an error of WSAEWOULDBLOCK - */
  801. /* anything else indicates a genuine error. */
  802. /********************************************************************/
  803. if ( status == SOCKET_ERROR )
  804. {
  805. status = WSAGetLastError();
  806. if (status != WSAEWOULDBLOCK)
  807. {
  808. TRC_ERR((TB, _T("Connect failed - GLE:%d"), status));
  809. DC_QUIT;
  810. }
  811. }
  812. //
  813. //set the send and receive buffers (reserves them)
  814. //
  815. sizeVal = TS_PROXY_WSRCVBUFSIZE;
  816. status = setsockopt( s, SOL_SOCKET, SO_RCVBUF, (char DCPTR) &sizeVal, sizeof( DCINT ));
  817. sizeVal = TS_PROXY_WSSNDBUFSIZE;
  818. status = setsockopt( s, SOL_SOCKET, SO_SNDBUF, (char DCPTR) &sizeVal, sizeof( DCINT ));
  819. //
  820. // Set keep-alive to false
  821. //
  822. optVal = false;
  823. status = setsockopt( s, SOL_SOCKET, SO_KEEPALIVE, (PCHAR)&optVal, sizeof(optVal));
  824. if (status == SOCKET_ERROR)
  825. {
  826. DC_QUIT;
  827. }
  828. lpServerContext = (LPSERVERLISTENTCONTEXT)HeapAlloc( GetProcessHeap(), 0, sizeof(SERVERLISTENTCONTEXT) );
  829. if (!lpServerContext)
  830. {
  831. DC_QUIT;
  832. }
  833. lpServerContext->bTerminate = FALSE;
  834. memcpy( &lpServerContext->s, &s, sizeof( s ));
  835. lpServerContext->lpECB = lpECB;
  836. serverThread = CreateThread( NULL, 0, ServerListenThread, lpServerContext, CREATE_SUSPENDED, NULL);
  837. if (!serverThread)
  838. {
  839. DC_QUIT;
  840. }
  841. lpReadContext = (LPREADCALLBACKCONTEXT)HeapAlloc( GetProcessHeap(), 0, sizeof(READCALLBACKCONTEXT) );
  842. if (!lpReadContext)
  843. {
  844. DC_QUIT;
  845. }
  846. lpReadContext->s = s;
  847. lpReadContext->serverListenThread = serverThread;
  848. lpReadContext->cbReadSoFar = 0;
  849. lpReadContext->lpECB = lpECB;
  850. //we have come this far, so we must have been successful
  851. //
  852. //start reading from client and send to server.
  853. //
  854. fSuccess = ReadFromClient( lpReadContext );
  855. DC_EXIT_POINT:
  856. if (lpstrUsername)
  857. {
  858. HeapFree(GetProcessHeap(),0,lpstrUsername);
  859. }
  860. if (serverThread)
  861. {
  862. if ( !fSuccess )
  863. {
  864. lpServerContext->bTerminate = TRUE;
  865. }
  866. dwResult = ResumeThread(serverThread);
  867. if (dwResult == -1)
  868. {
  869. fSuccess = FALSE;
  870. HeapFree(GetProcessHeap(),0,lpServerContext);
  871. lpServerContext = NULL;
  872. }
  873. }
  874. if ( !fSuccess )
  875. {
  876. if (serverThread)
  877. {
  878. CloseHandle(serverThread);
  879. }
  880. else if (lpServerContext)
  881. {
  882. HeapFree(GetProcessHeap(),0,lpServerContext);
  883. }
  884. if (lpReadContext)
  885. {
  886. HeapFree(GetProcessHeap(),0,lpReadContext);
  887. }
  888. if (s!=INVALID_SOCKET)
  889. {
  890. closesocket(s);
  891. }
  892. retValue = HSE_STATUS_ERROR;
  893. }
  894. else
  895. {
  896. retValue = HSE_STATUS_PENDING;
  897. }
  898. DC_END_FN();
  899. return retValue;
  900. }
  901. DWORD WINAPI
  902. ServerListenThread(
  903. IN LPVOID lpParameter
  904. )
  905. /*++
  906. Routine Description:
  907. This thread loops reading data from the server and forwarding it to the
  908. client. If an error occurrs we tell IIS to close the client connection
  909. and we then exit the thread.
  910. Arguments:
  911. lpParameter - Context specified when we created the thread.
  912. Return Value:
  913. 0 - Novody is checking the thread exit value so we just return 0/
  914. --*/
  915. {
  916. int read;
  917. BYTE buf[ TS_MAX_READ_SIZE ];
  918. SOCKET s;
  919. LPEXTENSION_CONTROL_BLOCK lpECB;
  920. BOOL result;
  921. DWORD dwBufferSize;
  922. DC_BEGIN_FN("ServerListenThread");
  923. s = ((LPSERVERLISTENTCONTEXT)lpParameter)->s;
  924. lpECB = ((LPSERVERLISTENTCONTEXT)lpParameter)->lpECB;
  925. if ( ((LPSERVERLISTENTCONTEXT)lpParameter)->bTerminate )
  926. {
  927. HeapFree( GetProcessHeap(), 0, lpParameter );
  928. return 0;
  929. }
  930. HeapFree( GetProcessHeap(), 0, lpParameter );
  931. lpParameter = NULL;
  932. WSASetLastError( 0 );
  933. char* temp = "tsdata";
  934. int nOffset = strlen( temp );
  935. while ( TRUE )
  936. {
  937. strcpy( (PCHAR)buf, "tsdata" );
  938. read = recv( s, (PCHAR)buf+nOffset, sizeof( buf ), 0);
  939. dwBufferSize = read;
  940. if( 0 >= read )
  941. {
  942. //something has gone wrong; bail
  943. read = WSAGetLastError();
  944. TRC_ERR((TB, _T("Reading from server failed - GLE:%d"), read));
  945. break;
  946. }
  947. result = lpECB->WriteClient( lpECB->ConnID, buf, &dwBufferSize, HSE_IO_SYNC|HSE_IO_NODELAY );
  948. if ( !result || dwBufferSize != read )
  949. {
  950. // There was a problem writing to the client.
  951. TRC_ERR((TB, _T("Writing to client failed - GLE:%d"), WSAGetLastError ()));
  952. break;
  953. }
  954. }
  955. //
  956. // If this fails there isn't anything we can do so we just ignore the
  957. // return code.
  958. //
  959. lpECB->ServerSupportFunction( lpECB->ConnID, HSE_REQ_CLOSE_CONNECTION, NULL, NULL, NULL );
  960. //
  961. // It is the read callbacks job to close the socket. We just exit here
  962. // since we closed client connection it should cause the callback
  963. // to cleanup the conneciton.
  964. //
  965. DC_END_FN();
  966. return 0;
  967. }
  968. /*++
  969. Routine Description:
  970. Reads data from client and sends to server if the data is contained within the ECB.
  971. If data is too large, just sets up an async read callback that IIS will call when data becomes available from the client
  972. Arguments:
  973. lpECB - Extension control block for the connection.
  974. lpReadContext - Read context that contains server socket, and other data
  975. Return Value:
  976. TRUE if successful
  977. FALSE if we could not send data to server or could not read from client
  978. --*/
  979. DWORD ReadFromClient( IN LPVOID lpParam )
  980. {
  981. BOOL result = FALSE;
  982. DWORD dwFlags;
  983. DWORD cbTotalToRead = TS_MAX_READ_SIZE;
  984. DWORD hseStatus = HSE_STATUS_PENDING;
  985. int sent;
  986. DWORD dwDataType;
  987. DC_BEGIN_FN("ReadFromClient");
  988. LPREADCALLBACKCONTEXT lpReadContext = (LPREADCALLBACKCONTEXT)lpParam;
  989. LPEXTENSION_CONTROL_BLOCK lpECB = lpReadContext->lpECB;
  990. //
  991. // Set a call back function and context that will
  992. // be used for handling asynchrnous IO operations.
  993. // This only needs to set up once.
  994. //
  995. CFRg( lpECB->ServerSupportFunction( lpECB->ConnID,HSE_REQ_IO_COMPLETION, ProxyReadCallback,NULL,(LPDWORD)lpReadContext ));
  996. dwDataType = HSE_IO_ASYNC;
  997. CFRg( lpECB->ServerSupportFunction( lpECB->ConnID,HSE_REQ_ASYNC_READ_CLIENT, lpReadContext->readBuffer, &cbTotalToRead, &dwDataType ));
  998. result = TRUE;
  999. END:
  1000. DC_END_FN();
  1001. return result;
  1002. }
  1003. VOID WINAPI
  1004. ProxyReadCallback(
  1005. IN LPEXTENSION_CONTROL_BLOCK lpECB,
  1006. IN PVOID pContext,
  1007. IN DWORD cbIO,
  1008. IN DWORD dwError
  1009. )
  1010. /*++
  1011. Routine Description:
  1012. Callback from IIS when data is received from the client. If any errors
  1013. occurr we close the socket to the server and wait for the server listening
  1014. thread to exit. When it exits we then tell IIS we are done with this
  1015. connection.
  1016. we just sit in an infinite loop reading from the client until the client closes the connection
  1017. Arguments:
  1018. lpECB - Extension control block for the connection.
  1019. pContext - Context we defined when requesting the async notification.
  1020. cbIO - Bytes read from the client. Zero indicates the connection closed.
  1021. dwError - Win32 error code for the read. Non-zero means there was an error.
  1022. Return Value:
  1023. None
  1024. --*/
  1025. {
  1026. LPREADCALLBACKCONTEXT lpReadContext;
  1027. int sent = 0;
  1028. DWORD cbTotalToRead;
  1029. DWORD dwDataType;
  1030. BOOL fResult = FALSE;
  1031. DC_BEGIN_FN("ProxyReadCallback");
  1032. lpReadContext = (LPREADCALLBACKCONTEXT)pContext;
  1033. if (dwError != 0 || cbIO == 0)
  1034. {
  1035. DC_QUIT;
  1036. }
  1037. WSASetLastError( 0 );
  1038. cbTotalToRead = sizeof( lpReadContext->readBuffer );
  1039. fResult = lpECB->ReadClient( lpECB->ConnID, lpReadContext->readBuffer, &cbTotalToRead );
  1040. if( !fResult || !cbTotalToRead )
  1041. {
  1042. TRC_ERR((TB, _T("Send failed - GLE:%d"), GetLastError ()));
  1043. DC_QUIT;
  1044. }
  1045. //send the information to the server
  1046. WSASetLastError( 0 );
  1047. sent = send( lpReadContext->s, lpReadContext->readBuffer, cbTotalToRead, 0 );
  1048. if (sent < 0 || (UINT)sent != cbTotalToRead )
  1049. {
  1050. TRC_ERR((TB, _T("Send failed - GLE:%d"), WSAGetLastError ()));
  1051. fResult = FALSE;
  1052. DC_QUIT;
  1053. }
  1054. //tell iis we want to keep reading
  1055. cbTotalToRead = sizeof( lpReadContext->readBuffer );
  1056. dwDataType = HSE_IO_ASYNC;
  1057. fResult = lpECB->ServerSupportFunction( lpECB->ConnID, HSE_REQ_ASYNC_READ_CLIENT, lpReadContext->readBuffer, &cbTotalToRead, &dwDataType );
  1058. /*
  1059. cbTotalToRead = lpECB->cbTotalBytes - lpReadContext->cbReadSoFar;
  1060. if ( cbTotalToRead > TS_PROXY_READ_SIZE )
  1061. {
  1062. cbTotalToRead = TS_PROXY_READ_SIZE;
  1063. }
  1064. dwDataType = HSE_IO_ASYNC;
  1065. fResult = lpECB->ServerSupportFunction( lpECB->ConnID, HSE_REQ_ASYNC_READ_CLIENT, lpReadContext->readBuffer, &cbTotalToRead, &dwDataType );
  1066. //something really went wrong since IIS is telling us it won't be able to give us any async data
  1067. if (!fResult)
  1068. {
  1069. break;
  1070. }
  1071. lpReadContext->cbReadSoFar += cbIO;
  1072. */
  1073. // Basically if anything in here fails we are in deep
  1074. // trouble. We can't really do much about the failures
  1075. // so we need to just keep going and hope it works.
  1076. // All that said. None of the calls in here should fail.
  1077. // By shutting down the socket we should force the server listen
  1078. // thread to exit since it is looping reading on the socket.
  1079. DC_EXIT_POINT:
  1080. if (!fResult )
  1081. {
  1082. closesocket( lpReadContext->s );
  1083. WaitForSingleObject( lpReadContext->serverListenThread,INFINITE );
  1084. CloseHandle( lpReadContext->serverListenThread );
  1085. lpECB->ServerSupportFunction( lpECB->ConnID, HSE_REQ_DONE_WITH_SESSION, NULL, NULL, NULL);
  1086. HeapFree( GetProcessHeap(),0, lpReadContext );
  1087. }
  1088. DC_END_FN();
  1089. }
  1090. DWORD
  1091. GetRegValueAsDword(
  1092. IN LPCSTR regValue,
  1093. IN DWORD dwDefaultValue
  1094. )
  1095. /*++
  1096. Routine Description:
  1097. This gets the requested DWORD value from the registry. If it is not found
  1098. then the default value is returned instead.
  1099. Arguments:
  1100. regValue - Name of the requested value.
  1101. defaultValue - Value to use if not found in the registry.
  1102. Return Value:
  1103. DWORD - Either the requested value or the default.
  1104. --*/
  1105. {
  1106. DWORD dwRetValue;
  1107. LPVOID lpRegValue;
  1108. DC_BEGIN_FN("GetRegValueAsDword");
  1109. lpRegValue = QueryRegistryData(regValue,REG_DWORD);
  1110. if (lpRegValue)
  1111. {
  1112. dwRetValue = *((LPDWORD)lpRegValue);
  1113. HeapFree(GetProcessHeap(),0,lpRegValue);
  1114. }
  1115. else
  1116. {
  1117. dwRetValue = dwDefaultValue;
  1118. }
  1119. DC_END_FN();
  1120. return dwRetValue;
  1121. }
  1122. LPSTR
  1123. GetRegValueAsAnsiString(
  1124. IN LPCSTR regValue,
  1125. LPSTR defaultValue
  1126. )
  1127. /*++
  1128. Routine Description:
  1129. This gets the requested string value from the registry. If it is not found
  1130. then the default string is returned instead. The returned string is always
  1131. allocated in the function so it must be de-allocated when it is no longer
  1132. needed.
  1133. Arguments:
  1134. regValue - Name of the requested value.
  1135. defaultValue - Value to use if not found in the registry.
  1136. Return Value:
  1137. Non NULL - The value requested (or the default).
  1138. NULL - There was not enough memory to allocate a buffer to hold
  1139. the default string.
  1140. --*/
  1141. {
  1142. LPVOID lpRegValue;
  1143. LPSTR retString;
  1144. DC_BEGIN_FN("GetRegValueAsAnsiString");
  1145. retString = NULL;
  1146. lpRegValue = QueryRegistryData(regValue,REG_SZ);
  1147. if (lpRegValue)
  1148. {
  1149. retString = (LPSTR)lpRegValue;
  1150. }
  1151. else
  1152. {
  1153. retString = (LPSTR)HeapAlloc(GetProcessHeap(),0,sizeof(CHAR) * (strlen(defaultValue) + 1));
  1154. if (!retString)
  1155. {
  1156. goto CLEANUP_AND_EXIT;
  1157. }
  1158. lstrcpyA(retString,defaultValue);
  1159. }
  1160. CLEANUP_AND_EXIT:
  1161. DC_END_FN();
  1162. return retString;
  1163. }
  1164. LPVOID
  1165. QueryRegistryData(
  1166. IN LPCSTR regValue,
  1167. IN DWORD typeRequested
  1168. )
  1169. /*++
  1170. Routine Description:
  1171. This gets the requested value from the registry if it
  1172. is of the given type. If it is memory is allocated
  1173. for the value and it is returned.
  1174. Arguments:
  1175. regValue - Name of the requested value.
  1176. typeRequested - Type of the registry value desired
  1177. Return Value:
  1178. Non NULL - The value requested.
  1179. NULL - There was an error getting the requested value
  1180. --*/
  1181. {
  1182. LONG retCode;
  1183. HKEY hRegKey;
  1184. LPBYTE lpValueData;
  1185. DWORD dwValueSize;
  1186. DWORD dwType;
  1187. BOOL failure;
  1188. DC_BEGIN_FN("QueryRegistryData");
  1189. hRegKey = NULL;
  1190. failure = FALSE;
  1191. lpValueData = NULL;
  1192. retCode = RegOpenKeyEx( HKEY_LOCAL_MACHINE, TS_PROXY_REG_KEY, 0, KEY_QUERY_VALUE, &hRegKey );
  1193. if (ERROR_SUCCESS != retCode)
  1194. {
  1195. failure = TRUE;
  1196. goto CLEANUP_AND_EXIT;
  1197. }
  1198. retCode = RegQueryValueExA(hRegKey,regValue,NULL,&dwType,NULL,&dwValueSize);
  1199. if (retCode != ERROR_SUCCESS)
  1200. {
  1201. failure = TRUE;
  1202. goto CLEANUP_AND_EXIT;
  1203. }
  1204. // Make sure the data is the type they requested
  1205. if (dwType != typeRequested)
  1206. {
  1207. failure = TRUE;
  1208. goto CLEANUP_AND_EXIT;
  1209. }
  1210. lpValueData = (LPBYTE)HeapAlloc(GetProcessHeap(),0,dwValueSize);
  1211. if (!lpValueData)
  1212. {
  1213. failure = TRUE;
  1214. goto CLEANUP_AND_EXIT;
  1215. }
  1216. retCode = RegQueryValueExA( hRegKey, regValue, NULL, &dwType, lpValueData, &dwValueSize );
  1217. if (retCode != ERROR_SUCCESS)
  1218. {
  1219. failure = TRUE;
  1220. goto CLEANUP_AND_EXIT;
  1221. }
  1222. CLEANUP_AND_EXIT:
  1223. if (failure)
  1224. {
  1225. if (lpValueData)
  1226. {
  1227. HeapFree(GetProcessHeap(),0,lpValueData);
  1228. lpValueData = NULL;
  1229. }
  1230. }
  1231. if (hRegKey)
  1232. {
  1233. RegCloseKey(hRegKey);
  1234. }
  1235. DC_END_FN();
  1236. return lpValueData;
  1237. }