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