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.

306 lines
9.6 KiB

  1. #include "stdafx.h"
  2. #if !defined(BITS_V12_ON_NT4)
  3. #include "proxy.tmh"
  4. #endif
  5. HRESULT
  6. CACHED_AUTOPROXY::Generate(
  7. const TCHAR Host[]
  8. )
  9. {
  10. if (GetTickCount() - m_TimeStamp > CACHED_PROXY_LIFETIME_IN_MSEC)
  11. {
  12. m_HostName = L"";
  13. }
  14. if (0 == _tcscmp( Host, m_HostName ))
  15. {
  16. LogInfo("using existing proxy info for '%S'", Host );
  17. return S_OK;
  18. }
  19. LogInfo( "detecting proxy for '%S'", Host );
  20. //
  21. // Detect IE settings and look up proxy if necessary.
  22. // Boilerplate from Stephen Sulzer.
  23. //
  24. WINHTTP_PROXY_INFO ProxyInfo;
  25. WINHTTP_AUTOPROXY_OPTIONS AutoProxyOptions;
  26. WINHTTP_CURRENT_USER_IE_PROXY_CONFIG IEProxyConfig;
  27. LPWSTR AutoConfigUrl = 0;
  28. BOOL fTryAutoProxy = FALSE;
  29. BOOL fSuccess = FALSE;
  30. //
  31. // This implicitly sets ProxyInfo.dwAccessType to zero, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY.
  32. // If there is no proxy, the WinHttp functions don't update it, and it will therefore stay that way.
  33. // But lpszProxy will be NULL so SetRequestProxy will work anyway.
  34. //
  35. ZeroMemory(&ProxyInfo, sizeof(ProxyInfo));
  36. ZeroMemory(&AutoProxyOptions, sizeof(AutoProxyOptions));
  37. ZeroMemory(&IEProxyConfig, sizeof(IEProxyConfig));
  38. if (WinHttpGetIEProxyConfigForCurrentUser(&IEProxyConfig))
  39. {
  40. LogInfo("got user's IE info");
  41. if (IEProxyConfig.fAutoDetect)
  42. {
  43. LogInfo("IE specifies auto-detect");
  44. AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
  45. AutoProxyOptions.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP |
  46. WINHTTP_AUTO_DETECT_TYPE_DNS_A;
  47. fTryAutoProxy = TRUE;
  48. }
  49. if (IEProxyConfig.lpszAutoConfigUrl)
  50. {
  51. LogInfo("IE specifies auto-config URL '%S'", IEProxyConfig.lpszAutoConfigUrl ? IEProxyConfig.lpszAutoConfigUrl : NullString );
  52. AutoProxyOptions.dwFlags |= WINHTTP_AUTOPROXY_CONFIG_URL;
  53. AutoProxyOptions.lpszAutoConfigUrl = IEProxyConfig.lpszAutoConfigUrl;
  54. AutoConfigUrl = IEProxyConfig.lpszAutoConfigUrl;
  55. fTryAutoProxy = TRUE;
  56. }
  57. AutoProxyOptions.fAutoLogonIfChallenged = TRUE;
  58. }
  59. else
  60. {
  61. LogInfo("no user IE info: %d", GetLastError());
  62. // WinHttpGetIEProxyForCurrentUser failed, try autodetection anyway...
  63. AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
  64. AutoProxyOptions.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP |
  65. WINHTTP_AUTO_DETECT_TYPE_DNS_A;
  66. fTryAutoProxy = TRUE;
  67. }
  68. if (fTryAutoProxy)
  69. {
  70. LogInfo("trying auto-detect...");
  71. fSuccess = WinHttpGetProxyForUrl( m_hInternet,
  72. Host,
  73. &AutoProxyOptions,
  74. &ProxyInfo
  75. );
  76. LogInfo("auto-detect returned %d (%d)", fSuccess, fSuccess ? 0 : GetLastError() );
  77. }
  78. // If we didn't do autoproxy or if it failed, see
  79. // if there's an explicit proxy server in the IE
  80. // proxy configuration...
  81. //
  82. // This is where the WinHttpGetIEProxyConfigForCurrentUser API
  83. // really comes in handy: in environments in which autoproxy is
  84. // not supported and so the user's IE browser must be
  85. // configured with an explicit proxy server.
  86. //
  87. if (!fTryAutoProxy || !fSuccess)
  88. {
  89. LogInfo("looking for backup ideas");
  90. if (IEProxyConfig.lpszProxy)
  91. {
  92. LogInfo("using named proxy '%S'", IEProxyConfig.lpszProxy ? IEProxyConfig.lpszProxy : NullString );
  93. ProxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
  94. ProxyInfo.lpszProxy = IEProxyConfig.lpszProxy;
  95. ProxyInfo.lpszProxyBypass = IEProxyConfig.lpszProxyBypass;
  96. }
  97. }
  98. //
  99. // If we are not using the proxy strings from IEProxyConfig, then we better delete them.
  100. //
  101. if (IEProxyConfig.lpszProxy && ProxyInfo.lpszProxy != IEProxyConfig.lpszProxy)
  102. {
  103. GlobalFree( IEProxyConfig.lpszProxy );
  104. IEProxyConfig.lpszProxy = NULL;
  105. }
  106. if (IEProxyConfig.lpszProxyBypass && ProxyInfo.lpszProxyBypass != IEProxyConfig.lpszProxyBypass)
  107. {
  108. GlobalFree( IEProxyConfig.lpszProxyBypass );
  109. IEProxyConfig.lpszProxyBypass = NULL;
  110. }
  111. //
  112. // Sometimes the registry contains a single or double colon for the proxy or, oddly, bypass list.
  113. // SetRequestProxy rejects them. Both cases should be treated like a NULL string.
  114. //
  115. static wchar_t SingleColon[] = L":";
  116. static wchar_t DoubleColon[] = L"::";
  117. if (ProxyInfo.lpszProxy)
  118. {
  119. if (0 == wcscmp( ProxyInfo.lpszProxy, SingleColon ) ||
  120. 0 == wcscmp( ProxyInfo.lpszProxy, DoubleColon ))
  121. {
  122. LogWarning("suppressing invalid proxy string %S", ProxyInfo.lpszProxy );
  123. GlobalFree( ProxyInfo.lpszProxy );
  124. ProxyInfo.lpszProxy = NULL;
  125. }
  126. }
  127. if (ProxyInfo.lpszProxyBypass)
  128. {
  129. if (0 == wcscmp( ProxyInfo.lpszProxyBypass, SingleColon ) ||
  130. 0 == wcscmp( ProxyInfo.lpszProxyBypass, DoubleColon ))
  131. {
  132. LogWarning("suppressing invalid bypass string %S", ProxyInfo.lpszProxyBypass );
  133. GlobalFree( ProxyInfo.lpszProxyBypass );
  134. ProxyInfo.lpszProxyBypass = NULL;
  135. }
  136. }
  137. LogInfo("proxy '%S'", ProxyInfo.lpszProxy ? ProxyInfo.lpszProxy : NullString );
  138. LogInfo("bypass list '%S'", ProxyInfo.lpszProxyBypass ? ProxyInfo.lpszProxyBypass : NullString );
  139. LogInfo("access type %d", ProxyInfo.dwAccessType );
  140. if (AutoConfigUrl)
  141. {
  142. GlobalFree( AutoConfigUrl );
  143. }
  144. Clear();
  145. m_ProxyInfo = ProxyInfo;
  146. m_HostName = Host;
  147. m_fValid = true;
  148. m_TimeStamp = GetTickCount();
  149. //
  150. // We don't have to release the proxy server and proxy bypass strings
  151. // because Clear() will do that.
  152. //
  153. return S_OK;
  154. }
  155. void
  156. CACHED_AUTOPROXY::Clear()
  157. {
  158. if (m_fValid)
  159. {
  160. m_fValid = false;
  161. if (m_ProxyInfo.lpszProxy) GlobalFree(m_ProxyInfo.lpszProxy);
  162. if (m_ProxyInfo.lpszProxyBypass) GlobalFree(m_ProxyInfo.lpszProxyBypass);
  163. }
  164. ZeroMemory(&m_ProxyInfo, sizeof(m_ProxyInfo));
  165. m_HostName = NULL;
  166. }
  167. PROXY_SETTINGS_CONTAINER::PROXY_SETTINGS_CONTAINER(
  168. LPCWSTR Url,
  169. const PROXY_SETTINGS * ProxySettings
  170. ) :
  171. m_ProxyUsage( ProxyUsageFromJobProxyUsage( ProxySettings->ProxyUsage )),
  172. m_ProxyList( NULL ),
  173. m_BypassList( NULL ),
  174. m_TokenCursor( NULL )
  175. {
  176. //
  177. // Set up the list of proxy servers.
  178. //
  179. switch (m_ProxyUsage)
  180. {
  181. case WINHTTP_ACCESS_TYPE_NO_PROXY:
  182. break;
  183. case WINHTTP_ACCESS_TYPE_NAMED_PROXY:
  184. {
  185. m_MasterProxyList = ProxySettings->ProxyList;
  186. m_BypassList = ProxySettings->ProxyBypassList;
  187. break;
  188. }
  189. case WINHTTP_ACCESS_TYPE_DEFAULT_PROXY:
  190. {
  191. THROW_HRESULT( g_ProxyCache->Generate( Url ));
  192. m_MasterProxyList = g_ProxyCache->GetProxyList();
  193. m_BypassList = g_ProxyCache->GetBypassList();
  194. m_AccessType = g_ProxyCache->GetAccessType();
  195. break;
  196. }
  197. default:
  198. ASSERT( 0 );
  199. break;
  200. }
  201. ResetCurrentProxy();
  202. }
  203. HRESULT
  204. SetRequestProxy(
  205. HINTERNET hRequest,
  206. PROXY_SETTINGS_CONTAINER * ProxySettings
  207. )
  208. {
  209. WINHTTP_PROXY_INFO ProxyInfo;
  210. ProxyInfo.dwAccessType = ProxySettings->GetProxyUsage();
  211. ProxyInfo.lpszProxy = const_cast<LPWSTR>( ProxySettings->GetCurrentProxy() );
  212. ProxyInfo.lpszProxyBypass = const_cast<LPWSTR>( ProxySettings->GetBypassList() );
  213. LogInfo("proxy info:");
  214. LogInfo("access: %d", ProxyInfo.dwAccessType );
  215. LogInfo("server '%S'", ProxyInfo.lpszProxy ? ProxyInfo.lpszProxy : NullString );
  216. LogInfo("bypass '%S'", ProxyInfo.lpszProxyBypass ? ProxyInfo.lpszProxyBypass : NullString );
  217. if (ProxyInfo.dwAccessType == WINHTTP_ACCESS_TYPE_NO_PROXY)
  218. {
  219. LogInfo("proxy usage disabled");
  220. return S_OK;
  221. }
  222. if (ProxyInfo.lpszProxy == NULL)
  223. {
  224. LogInfo("null proxy");
  225. return S_OK;
  226. }
  227. if (ProxyInfo.dwAccessType == WINHTTP_ACCESS_TYPE_DEFAULT_PROXY)
  228. {
  229. LogInfo("mapping PRECONFIG to named proxy");
  230. ProxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
  231. }
  232. if (!WinHttpSetOption( hRequest,
  233. WINHTTP_OPTION_PROXY,
  234. &ProxyInfo,
  235. sizeof(ProxyInfo)
  236. ))
  237. {
  238. DWORD err = GetLastError();
  239. LogWarning( "can't set proxy option: %!winerr!", err );
  240. return HRESULT_FROM_WIN32( err );
  241. }
  242. return S_OK;
  243. }
  244. bool IsPossibleProxyFailure( DWORD err )
  245. {
  246. switch (err)
  247. {
  248. case ERROR_WINHTTP_NAME_NOT_RESOLVED:
  249. case ERROR_WINHTTP_CANNOT_CONNECT:
  250. case ERROR_WINHTTP_CONNECTION_ERROR:
  251. case ERROR_WINHTTP_TIMEOUT:
  252. return true;
  253. default:
  254. return false;
  255. }
  256. }