1 /****************************************************************************
2 * *
3 * Network Stream Proxy Management *
4 * Copyright Peter Gutmann 1993-2007 *
5 * *
6 ****************************************************************************/
7
8 #if defined( INC_ALL )
9 #include "stream_int.h"
10 #else
11 #include "io/stream_int.h"
12 #endif /* Compiler-specific includes */
13
14 #ifdef USE_TCP
15
16 /****************************************************************************
17 * *
18 * SOCKS Proxy Management *
19 * *
20 ****************************************************************************/
21
22 /* Open a connection through a Socks proxy. This is currently disabled
23 since it doesn't appear to be used by anyone */
24
25 #if 0
26
27 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
28 int connectViaSocksProxy( INOUT STREAM *stream )
29 {
30 MESSAGE_DATA msgData;
31 BYTE socksBuffer[ 64 + CRYPT_MAX_TEXTSIZE + 8 ], *bufPtr = socksBuffer;
32 char userName[ CRYPT_MAX_TEXTSIZE + 8 ];
33 int length, status;
34
35 assert( isWritePtr( stream, sizeof( STREAM ) ) );
36
37 REQUIRES_S( stream->type == STREAM_TYPE_NETWORK );
38
39 /* Get the SOCKS user name, defaulting to "cryptlib" if there's none
40 set */
41 setMessageData( &msgData, userName, CRYPT_MAX_TEXTSIZE );
42 status = krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE,
43 IMESSAGE_GETATTRIBUTE_S, &msgData,
44 CRYPT_OPTION_NET_SOCKS_USERNAME );
45 if( cryptStatusOK( status ) )
46 userName[ msgData.length ] = '\0';
47 else
48 strlcpy_s( userName, CRYPT_MAX_TEXTSIZE, "cryptlib" );
49
50 /* Build up the SOCKSv4 request string:
51
52 BYTE: version = 4
53 BYTE: command = 1 (connect)
54 WORD: port
55 LONG: IP address
56 STRING: userName + '\0'
57
58 Note that this has a potential problem in that it requires a DNS
59 lookup by the client, which can lead to problems if the client
60 can't get DNS requests out because only SOCKSified access is allowed.
61 A related problem occurs when SOCKS is being used as a tunnelling
62 interface because the DNS lookup will communicate data about the
63 client to an observer outside the tunnel.
64
65 To work around this there's a so-called SOCKSv4a protocol that has
66 the SOCKS proxy perform the lookup:
67
68 BYTE: version = 4
69 BYTE: command = 1 (connect)
70 WORD: port
71 LONG: IP address = 0x00 0x00 0x00 0xFF
72 STRING: userName + '\0'
73 STRING: FQDN + '\0'
74
75 Unfortunately there's no way to tell whether a SOCKS server supports
76 4a or only 4, but in any case since SOCKS support is currently
77 disabled we leave the poke-and-hope 4a detection until such time as
78 someone actually requests it */
79 *bufPtr++ = 4; *bufPtr++ = 1;
80 mputWord( bufPtr, netStream->port );
81 status = getIPAddress( stream, bufPtr, netStream->host );
82 strlcpy_s( bufPtr + 4, CRYPT_MAX_TEXTSIZE, userName );
83 length = 1 + 1 + 2 + 4 + strlen( userName ) + 1;
84 if( cryptStatusError( status ) )
85 {
86 netStream->transportDisconnectFunction( stream, TRUE );
87 return( status );
88 }
89
90 /* Send the data to the server and read back the reply */
91 status = netStream->transportWriteFunction( stream, socksBuffer, length,
92 TRANSPORT_FLAG_FLUSH );
93 if( cryptStatusOK( status ) )
94 status = netStream->transportReadFunction( stream, socksBuffer, 8,
95 TRANSPORT_FLAG_BLOCKING );
96 if( cryptStatusError( status ) )
97 {
98 /* The involvement of a proxy complicates matters somewhat because
99 we can usually connect to the proxy OK but may run into problems
100 going from the proxy to the remote server, so if we get an error
101 at this stage (which will typically show up as a read error from
102 the proxy) we report it as an open error instead */
103 if( status == CRYPT_ERROR_READ || status == CRYPT_ERROR_COMPLETE )
104 status = CRYPT_ERROR_OPEN;
105 netStream->transportDisconnectFunction( stream, TRUE );
106 return( status );
107 }
108
109 /* Make sure that everything is OK:
110
111 BYTE: null = 0
112 BYTE: status = 90 (OK)
113 WORD: port
114 LONG: IP address */
115 if( socksBuffer[ 1 ] != 90 )
116 {
117 int i;
118
119 netStream->transportDisconnectFunction( stream, TRUE );
120 strlcpy_s( netStream->errorInfo->errorString, MAX_ERRMSG_SIZE,
121 "Socks proxy returned" );
122 for( i = 0; i < 8; i++ )
123 {
124 sprintf_s( netStream->errorInfo->errorString + 20 + ( i * 3 ),
125 MAX_ERRMSG_SIZE - ( 20 + ( i * 3 ) ), " %02X",
126 socksBuffer[ i ] );
127 }
128 strlcat_s( netStream->errorInfo->errorString, MAX_ERRMSG_SIZE, "." );
129 netStream->errorCode = socksBuffer[ 1 ];
130 return( CRYPT_ERROR_OPEN );
131 }
132
133 return( CRYPT_OK );
134 }
135 #endif /* 0 */
136
137 /****************************************************************************
138 * *
139 * HTTP Proxy Management *
140 * *
141 ****************************************************************************/
142
143 #ifdef USE_HTTP
144
145 /* Open a connection via an HTTP proxy */
146
147 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
connectViaHttpProxy(INOUT STREAM * stream,INOUT ERROR_INFO * errorInfo)148 int connectViaHttpProxy( INOUT STREAM *stream,
149 INOUT ERROR_INFO *errorInfo )
150 {
151 NET_STREAM_INFO *netStream = ( NET_STREAM_INFO * ) stream->netStreamInfo;
152 const STM_WRITE_FUNCTION writeFunction = \
153 FNPTR_GET( netStream->writeFunction );
154 const STM_READ_FUNCTION readFunction = \
155 FNPTR_GET( netStream->readFunction );
156 const STM_TRANSPORTDISCONNECT_FUNCTION transportDisconnectFunction = \
157 FNPTR_GET( netStream->transportDisconnectFunction );
158 HTTP_DATA_INFO httpDataInfo;
159 BYTE buffer[ 64 + 8 ];
160 int length, status;
161
162 assert( isWritePtr( stream, sizeof( STREAM ) ) );
163 assert( isWritePtr( errorInfo, sizeof( ERROR_INFO ) ) );
164
165 REQUIRES_S( netStream != NULL );
166 REQUIRES_S( stream->type == STREAM_TYPE_NETWORK );
167 REQUIRES_S( writeFunction != NULL );
168 REQUIRES_S( readFunction != NULL );
169 REQUIRES_S( transportDisconnectFunction != NULL );
170
171 /* Open the connection via the proxy. To do this we temporarily layer
172 HTTP I/O over the TCP I/O, then once the proxy messaging has been
173 completed we re-set the stream to pure TCP I/O and clear any stream
174 flags that were set during the proxying */
175 setStreamLayerHTTP( netStream );
176 initHttpDataInfo( &httpDataInfo, "", 0 );
177 status = writeFunction( stream, &httpDataInfo, sizeof( HTTP_DATA_INFO ),
178 &length );
179 if( cryptStatusOK( status ) )
180 {
181 initHttpDataInfo( &httpDataInfo, buffer, 64 );
182 status = readFunction( stream, &httpDataInfo,
183 sizeof( HTTP_DATA_INFO ), &length );
184 }
185 setStreamLayerDirect( netStream );
186 stream->flags = 0;
187 if( cryptStatusError( status ) )
188 {
189 /* The involvement of a proxy complicates matters somewhat because
190 we can usually connect to the proxy OK but may run into problems
191 going from the proxy to the remote server so if we get an error
192 at this stage (which will typically show up as a read error from
193 the proxy) we report it as an open error instead */
194 if( status == CRYPT_ERROR_READ || status == CRYPT_ERROR_COMPLETE )
195 status = CRYPT_ERROR_OPEN;
196 copyErrorInfo( errorInfo, NETSTREAM_ERRINFO );
197 transportDisconnectFunction( netStream, TRUE );
198 }
199
200 return( status );
201 }
202 #endif /* USE_HTTP */
203
204 /****************************************************************************
205 * *
206 * Proxy Autoconfig Management *
207 * *
208 ****************************************************************************/
209
210 /* Try and auto-detect HTTP proxy information */
211
212 #if defined( __WIN32__ )
213
214 /* The autoproxy functions were only documented in WinHTTP 5.1 so we have to
215 provide the necessary defines and structures ourselves */
216
217 #ifndef WINHTTP_ACCESS_TYPE_DEFAULT_PROXY
218
219 #define HINTERNET HANDLE
220
221 typedef struct {
222 DWORD dwFlags;
223 DWORD dwAutoDetectFlags;
224 LPCWSTR lpszAutoConfigUrl;
225 LPVOID lpvReserved;
226 DWORD dwReserved;
227 BOOL fAutoLogonIfChallenged;
228 } WINHTTP_AUTOPROXY_OPTIONS;
229
230 typedef struct {
231 DWORD dwAccessType;
232 LPWSTR lpszProxy;
233 LPWSTR lpszProxyBypass;
234 } WINHTTP_PROXY_INFO;
235
236 typedef struct {
237 BOOL fAutoDetect;
238 LPWSTR lpszAutoConfigUrl;
239 LPWSTR lpszProxy;
240 LPWSTR lpszProxyBypass;
241 } WINHTTP_CURRENT_USER_IE_PROXY_CONFIG;
242
243 #define WINHTTP_AUTOPROXY_AUTO_DETECT 1
244 #define WINHTTP_AUTO_DETECT_TYPE_DHCP 1
245 #define WINHTTP_AUTO_DETECT_TYPE_DNS_A 2
246 #define WINHTTP_ACCESS_TYPE_NO_PROXY 1
247 #define WINHTTP_NO_PROXY_NAME NULL
248 #define WINHTTP_NO_PROXY_BYPASS NULL
249
250 #endif /* WinHTTP 5.1 defines and structures */
251
252 typedef HINTERNET ( *WINHTTPOPEN )( LPCWSTR pwszUserAgent, DWORD dwAccessType,
253 LPCWSTR pwszProxyName, LPCWSTR pwszProxyBypass,
254 DWORD dwFlags );
255 typedef BOOL ( *WINHTTPGETDEFAULTPROXYCONFIGURATION )( WINHTTP_PROXY_INFO* pProxyInfo );
256 typedef BOOL ( *WINHTTPGETIEPROXYCONFIGFORCURRENTUSER )(
257 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *pProxyConfig );
258 typedef BOOL ( *WINHTTPGETPROXYFORURL )( HINTERNET hSession, LPCWSTR lpcwszUrl,
259 WINHTTP_AUTOPROXY_OPTIONS *pAutoProxyOptions,
260 WINHTTP_PROXY_INFO *pProxyInfo );
261 typedef BOOL ( *WINHTTPCLOSEHANDLE )( HINTERNET hInternet );
262
263 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
findProxyUrl(OUT_BUFFER (proxyMaxLen,* proxyLen)char * proxy,IN_LENGTH_DNS const int proxyMaxLen,OUT_LENGTH_BOUNDED_Z (proxyMaxLen)int * proxyLen,IN_BUFFER (urlLen)const char * url,IN_LENGTH_DNS const int urlLen)264 int findProxyUrl( OUT_BUFFER( proxyMaxLen, *proxyLen ) char *proxy,
265 IN_LENGTH_DNS const int proxyMaxLen,
266 OUT_LENGTH_BOUNDED_Z( proxyMaxLen ) int *proxyLen,
267 IN_BUFFER( urlLen ) const char *url,
268 IN_LENGTH_DNS const int urlLen )
269 {
270 static HMODULE hWinHTTP = NULL;
271 static WINHTTPOPEN pWinHttpOpen = NULL;
272 static WINHTTPGETDEFAULTPROXYCONFIGURATION pWinHttpGetDefaultProxyConfiguration = NULL;
273 static WINHTTPGETIEPROXYCONFIGFORCURRENTUSER pWinHttpGetIEProxyConfigForCurrentUser = NULL;
274 static WINHTTPGETPROXYFORURL pWinHttpGetProxyForUrl = NULL;
275 static WINHTTPCLOSEHANDLE pWinHttpCloseHandle = NULL;
276 WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions = \
277 { WINHTTP_AUTOPROXY_AUTO_DETECT,
278 WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A,
279 NULL, NULL, 0, FALSE };
280 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ieProxyInfo;
281 WINHTTP_PROXY_INFO proxyInfo;
282 HINTERNET hSession;
283 char urlBuffer[ MAX_DNS_SIZE + 1 + 8 ];
284 wchar_t unicodeURL[ MAX_DNS_SIZE + 1 + 8 ];
285 size_t unicodeUrlLen, wcsProxyLen;
286 int offset, length, proxyStatus;
287
288 assert( isWritePtr( proxy, proxyMaxLen ) );
289 assert( isWritePtr( proxyLen, sizeof( int ) ) );
290 assert( isReadPtr( url, urlLen ) );
291
292 REQUIRES( proxyMaxLen >= 10 && proxyMaxLen <= MAX_DNS_SIZE );
293 REQUIRES( urlLen > 0 && urlLen <= MAX_DNS_SIZE );
294
295 /* Under Win2K SP3 and Windows XP and newer (2003, Vista, etc), or at
296 least Windows versions with WinHTTP 5.1 installed in some way (it
297 officially shipped with the versions mentioned earlier) we can use
298 WinHTTP AutoProxy support, which implements the Web Proxy Auto-
299 Discovery (WPAD) protocol from an internet draft that expired in May
300 2001. Under older versions of Windows we have to use the WinINet
301 InternetGetProxyInfo, however this consists of a ghastly set of
302 kludges that were never meant to be exposed to the outside world
303 (they were only crowbarred out of MS as part of the DoJ consent
304 decree) and user experience with them is that they don't really work
305 except in the one special way in which MS-internal code calls them.
306 Since we don't know what this is, we use the WinHTTP functions
307 instead */
308 if( hWinHTTP == NULL )
309 {
310 if( ( hWinHTTP = DynamicLoad( "WinHTTP.dll" ) ) == NULL )
311 return( CRYPT_ERROR_NOTFOUND );
312
313 pWinHttpOpen = ( WINHTTPOPEN ) \
314 GetProcAddress( hWinHTTP, "WinHttpOpen" );
315 pWinHttpGetDefaultProxyConfiguration = ( WINHTTPGETDEFAULTPROXYCONFIGURATION ) \
316 GetProcAddress( hWinHTTP, "WinHttpGetDefaultProxyConfiguration" );
317 pWinHttpGetIEProxyConfigForCurrentUser = ( WINHTTPGETIEPROXYCONFIGFORCURRENTUSER ) \
318 GetProcAddress( hWinHTTP, "WinHttpGetIEProxyConfigForCurrentUser" );
319 pWinHttpGetProxyForUrl = ( WINHTTPGETPROXYFORURL ) \
320 GetProcAddress( hWinHTTP, "WinHttpGetProxyForUrl" );
321 pWinHttpCloseHandle = ( WINHTTPCLOSEHANDLE ) \
322 GetProcAddress( hWinHTTP, "WinHttpCloseHandle" );
323 if( pWinHttpOpen == NULL || pWinHttpGetProxyForUrl == NULL || \
324 pWinHttpCloseHandle == NULL )
325 {
326 DynamicUnload( hWinHTTP );
327 return( CRYPT_ERROR_NOTFOUND );
328 }
329 }
330
331 /* Autoproxy discovery using WinHttpGetProxyForUrl() can be awfully slow,
332 often taking several seconds since it requires probing for proxy info
333 first using DHCP and then if that fails using DNS. Since this is done
334 via a blocking call everything blocks while it's in progress. To help
335 mitigate this we try for proxy info direct from the registry if it's
336 available, avoiding the lengthy autodiscovery process. This also
337 means that discovery will work if no auto-discovery support is present,
338 for example on servers where the admin has set the proxy config
339 directly with ProxyCfg.exe */
340 if( pWinHttpGetDefaultProxyConfiguration != NULL && \
341 pWinHttpGetDefaultProxyConfiguration( &proxyInfo ) && \
342 proxyInfo.lpszProxy != NULL )
343 {
344 proxyStatus = wcstombs_s( &wcsProxyLen, proxy, proxyMaxLen,
345 proxyInfo.lpszProxy, MAX_DNS_SIZE );
346 GlobalFree( proxyInfo.lpszProxy );
347 if( proxyInfo.lpszProxyBypass != NULL )
348 GlobalFree( proxyInfo.lpszProxyBypass );
349 if( proxyStatus == 0 )
350 {
351 *proxyLen = wcsProxyLen;
352 return( CRYPT_OK );
353 }
354 }
355
356 /* The next fallback is to get the proxy info from MSIE. This is also
357 usually much quicker than WinHttpGetProxyForUrl() although sometimes
358 it seems to fall back to that, based on the longish delay involved.
359 Another issue with this is that it won't work in a service process
360 that isn't impersonating an interactive user (since there isn't a
361 current user), but in that case we just fall back to
362 WinHttpGetProxyForUrl() */
363 if( pWinHttpGetIEProxyConfigForCurrentUser != NULL && \
364 pWinHttpGetIEProxyConfigForCurrentUser( &ieProxyInfo ) )
365 {
366 proxyStatus = wcstombs_s( &wcsProxyLen, proxy, proxyMaxLen,
367 ieProxyInfo.lpszProxy, MAX_DNS_SIZE );
368 if( ieProxyInfo.lpszAutoConfigUrl != NULL )
369 GlobalFree( ieProxyInfo.lpszAutoConfigUrl );
370 if( ieProxyInfo.lpszProxy != NULL )
371 GlobalFree( ieProxyInfo.lpszProxy );
372 if( ieProxyInfo.lpszProxyBypass != NULL )
373 GlobalFree( ieProxyInfo.lpszProxyBypass );
374 if( proxyStatus == 0 )
375 {
376 *proxyLen = wcsProxyLen;
377 return( CRYPT_OK );
378 }
379 }
380
381 /* WinHttpGetProxyForUrl() requires a schema for the URL that it's
382 performing a lookup on, if the URL doesn't contain one we use a
383 default value of "http://". In addition we need to convert the
384 raw octet string into a null-terminated string for the mbstowcs_s()
385 Unicode conversion and following WinHttpGetProxyForUrl() lookup */
386 if( strFindStr( url, urlLen, "://", 3 ) < 0 )
387 {
388 strlcpy_s( urlBuffer, MAX_DNS_SIZE, "http://" );
389 offset = 7;
390 length = MAX_DNS_SIZE - offset;
391 }
392 else
393 {
394 /* There's already a schema present, not need to manually add one */
395 offset = 0;
396 length = urlLen;
397 }
398 memcpy( urlBuffer + offset, url, length );
399 urlBuffer[ offset + length ] = '\0';
400
401 /* Locate the proxy used for accessing the resource at the supplied URL.
402 We have to convert to and from Unicode because the WinHTTP functions
403 all take Unicode strings as args.
404
405 WinHttpGetProxyForUrl() can be rather flaky, in some cases it'll fail
406 instantly (without even trying auto-discovery) with GetLastError() =
407 87 (parameter error) but then calling it again some time later works
408 fine. Because of this we leave it as the last resort after trying
409 all of the other get-proxy mechanisms */
410 hSession = pWinHttpOpen( L"cryptlib/1.0",
411 WINHTTP_ACCESS_TYPE_NO_PROXY,
412 WINHTTP_NO_PROXY_NAME,
413 WINHTTP_NO_PROXY_BYPASS, 0 );
414 if( hSession == NULL )
415 return( CRYPT_ERROR_NOTFOUND );
416 if( mbstowcs_s( &unicodeUrlLen, unicodeURL, MAX_DNS_SIZE,
417 urlBuffer, MAX_DNS_SIZE ) != 0 )
418 {
419 pWinHttpCloseHandle( hSession );
420 return( CRYPT_ERROR_NOTFOUND );
421 }
422 unicodeURL[ unicodeUrlLen ] = L'\0';
423 memset( &proxyInfo, 0, sizeof( WINHTTP_PROXY_INFO ) );
424 if( pWinHttpGetProxyForUrl( hSession, unicodeURL, &autoProxyOptions,
425 &proxyInfo ) != TRUE )
426 {
427 pWinHttpCloseHandle( hSession );
428 return( CRYPT_ERROR_NOTFOUND );
429 }
430 proxyStatus = wcstombs_s( &wcsProxyLen, proxy, proxyMaxLen,
431 proxyInfo.lpszProxy, MAX_DNS_SIZE );
432 GlobalFree( proxyInfo.lpszProxy );
433 if( proxyInfo.lpszProxyBypass != NULL )
434 GlobalFree( proxyInfo.lpszProxyBypass );
435 pWinHttpCloseHandle( hSession );
436 if( proxyStatus != 0 )
437 return( CRYPT_ERROR_NOTFOUND );
438 *proxyLen = wcsProxyLen;
439
440 return( CRYPT_OK );
441 }
442
443 #if 0
444
445 typedef BOOL ( WINAPI *INTERNETGETPROXYINFO )( LPCSTR lpszUrl, DWORD dwUrlLength,
446 LPSTR lpszUrlHostName, DWORD dwUrlHostNameLength,
447 LPSTR* lplpszProxyHostName,
448 LPDWORD lpdwProxyHostNameLength );
449 typedef BOOL ( WINAPI *INTERNETINITIALIZEAUTOPROXYDLL )( DWORD dwVersion,
450 LPSTR lpszDownloadedTempFile, LPSTR lpszMime,
451 AutoProxyHelperFunctions* lpAutoProxyCallbacks,
452 LPAUTO_PROXY_SCRIPT_BUFFER lpAutoProxyScriptBuffer );
453
454 static int findProxyUrl( char *proxy, const int proxyMaxLen,
455 const char *url, const int urlLen )
456 {
457 static INTERNETGETPROXYINFO pInternetGetProxyInfo = NULL;
458 static INTERNETINITIALIZEAUTOPROXYDLL pInternetInitializeAutoProxyDll = NULL;
459 URL_INFO urlInfo;
460 char urlHost[ MAX_DNS_SIZE + 8 ];
461 char *proxyHost = NULL;
462 int proxyHostLen, status;
463
464 assert( isWritePtr( proxy, proxyMaxLen ) );
465 assert( isReadPtr( url, urlLen ) );
466
467 REQUIRES( proxyMaxLen > 10 && proxyMaxLen < MAX_INTLENGTH_SHORT );
468 REQUIRES( urlLen > 0 && urlLen < MAX_INTLENGTH_SHORT );
469
470 /* This gets somewhat complicated, under Win2K SP3 and XP and newer (or
471 at least Windows versions with WinHTTP 5.1 installed in some way, it
472 officially shipped with the versions mentioned earlier) we can use
473 WinHTTP AutoProxy support, which implements the Web Proxy Auto-
474 Discovery (WPAD) protocol from an internet draft that expired in May
475 2001. Under older versions of Windows we have to use the WinINet
476 InternetGetProxyInfo.
477
478 These functions were never meant to be used by the general public
479 (see the comment below) so they work in an extremely peculiar way
480 and only with the exact calling sequence that's used by MS code - it
481 looks like they were only intended as components of Windows-internal
482 implementation of proxy support since they require manual handling
483 of proxy config script downloading, parsing, and all manner of other
484 stuff that really doesn't concern us. Because of the extreme
485 difficulty in doing anything with these functions we use the WinHTTP
486 approach instead */
487 if( pInternetGetProxyInfo == NULL )
488 {
489 HMODULE hModJS;
490
491 if( ( hModJS = DynamicLoad( "JSProxy.dll" ) ) == NULL )
492 return( CRYPT_ERROR_NOTFOUND );
493
494 pInternetGetProxyInfo = ( INTERNETGETPROXYINFO ) \
495 GetProcAddress( hModJS, "InternetGetProxyInfo" );
496 pInternetInitializeAutoProxyDll = ( INTERNETINITIALIZEAUTOPROXYDLL ) \
497 GetProcAddress( hModJS, "InternetInitializeAutoProxyDll" );
498 if( pInternetGetProxyInfo == NULL || \
499 pInternetInitializeAutoProxyDll == NULL )
500 {
501 DynamicUnload( hModJS );
502 return( CRYPT_ERROR_NOTFOUND );
503 }
504
505 pInternetInitializeAutoProxyDll( 0, TempFile, NULL,
506 &HelperFunctions, NULL )
507 }
508
509 /* InternetGetProxyInfo() is a somewhat screwball undocumented function
510 that was crowbarred out of MS as part of the DoJ consent decree. It
511 takes as input four parameters that do the work of a single
512 parameter, the null-terminated target URL string. The documentation
513 for the function was initially wrong but has since been partially
514 corrected in places after user complaints, although there are still
515 missing parts as well as possible errors (why is it necessary to
516 specify a length for a supposedly null-terminated string?). In order
517 to meet the strange input-parameter requirements we have to pre-
518 parse the target URL in order to provide the various bits and pieces
519 that InternetGetProxyInfo() requires */
520 status = parseURL( &urlInfo, url, strlen( url ), 80, URL_TYPE_HTTP );
521 if( cryptStatusError( status ) )
522 return( status );
523 if( urlInfo.hostLen > MAX_DNS_SIZE )
524 return( CRYPT_ERROR_OVERFLOW );
525 memcpy( urlHost, urlInfo.host, urlInfo.hostLen );
526 urlHost[ urlInfo.hostLen ] = '\0';
527 if( !pInternetGetProxyInfo( url, strlen( url ), urlHost, urlInfo.hostLen,
528 &proxyHost, &proxyHostLen ) )
529 return( CRYPT_ERROR_NOTFOUND );
530 memcpy( proxy, proxyHost, proxyHostLen );
531 proxy[ proxyHostLen ] = '\0';
532 GlobalFree( proxyHost );
533 return( CRYPT_OK );
534 }
535 #endif /* 0 */
536
537 #endif /* Win32 */
538
539 #endif /* USE_TCP */
540