dirmngr: Implement automatic proxy detection on Windows.

* dirmngr/http.c [W32]: Include winhttp.h
(w32_get_internet_session): New.
(w32_get_proxy): New.
(get_proxy_for_url): Implement automatic proxy detection and fix error
in last patch.
(http_reinitialize): New.
* dirmngr/dirmngr.c (dirmngr_sighup_action): Call reinitialize.
* dirmngr/Makefile.am (NETLIBS) [W32]: Link with winhttp.
--

GnuPG-bug-id: 5768
This commit is contained in:
Werner Koch 2023-09-19 15:04:49 +02:00
parent fed33baed1
commit 1e120f5a8d
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
5 changed files with 166 additions and 4 deletions

View File

@ -68,6 +68,7 @@ AM_CFLAGS = $(USE_C99_CFLAGS) \
if HAVE_W32_SYSTEM
ldap_url = ldap-url.h ldap-url.c
NETLIBS += -lwinhttp
else
ldap_url =
endif

View File

@ -2045,6 +2045,7 @@ dirmngr_sighup_action (void)
crl_cache_deinit ();
cert_cache_init (hkp_cacert_filenames);
crl_cache_init ();
http_reinitialize ();
reload_dns_stuff (0);
ks_hkp_reload ();
}

View File

@ -22,4 +22,6 @@
const char *get_default_keyserver (int name_only);
void http_reinitialize (void);
#endif /* HTTP_COMMON_H */

View File

@ -64,6 +64,7 @@
# include <winsock2.h>
# endif
# include <windows.h>
# include <winhttp.h>
# ifndef EHOSTUNREACH
# define EHOSTUNREACH WSAEHOSTUNREACH
# endif
@ -1827,6 +1828,141 @@ release_proxy_info (proxy_info_t proxy)
}
/* Return an http session object. If clear is set, the object is
* destroyed. On error nULL is returned. */
#ifdef HAVE_W32_SYSTEM
static HINTERNET
w32_get_internet_session (int clear)
{
static HINTERNET session;
if (clear)
{
if (session)
{
WinHttpCloseHandle (session);
session = NULL;
}
return NULL;
}
if (!session)
{
session = WinHttpOpen (L"GnuPG dirmngr",
WINHTTP_ACCESS_TYPE_NO_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS,
0);
if (!session)
{
log_error ("WinHttpOpen failed: %s\n", w32_strerror (-1));
return NULL;
}
}
return session;
}
#endif /*HAVE_W32_SYSTEM*/
/* Return a proxy using a Windows API. */
#ifdef HAVE_W32_SYSTEM
static char *
w32_get_proxy (const char *url)
{
WINHTTP_AUTOPROXY_OPTIONS options = {0};
WINHTTP_PROXY_INFO info;
char *result = NULL;
char *p;
wchar_t *wurl;
int defaultcfg = 0;
wurl = utf8_to_wchar (url);
if (!wurl)
{
log_error ("utf8_to_wchar failed: %s\n",
gpg_strerror (gpg_error_from_syserror ()));
return NULL;
}
options.dwFlags = (WINHTTP_AUTOPROXY_ALLOW_AUTOCONFIG
| WINHTTP_AUTOPROXY_ALLOW_CM
| WINHTTP_AUTOPROXY_ALLOW_STATIC
| WINHTTP_AUTOPROXY_AUTO_DETECT
| WINHTTP_AUTOPROXY_SORT_RESULTS);
options.dwAutoDetectFlags = (WINHTTP_AUTO_DETECT_TYPE_DHCP
| WINHTTP_AUTO_DETECT_TYPE_DNS_A);
options.fAutoLogonIfChallenged = TRUE;
if (opt_debug)
log_debug ("calling WinHttpGetProxyForUrl (%s)\n", url);
if (!WinHttpGetProxyForUrl (w32_get_internet_session (0),
wurl, &options, &info))
{
int ec = (int)GetLastError ();
if (ec == ERROR_WINHTTP_AUTODETECTION_FAILED)
{
if (opt_debug)
log_debug ("calling WinHttpGetDefaultProxyConfiguration\n");
if (!WinHttpGetDefaultProxyConfiguration (&info))
{
if (opt_verbose)
log_info ("WinHttpGetDefaultProxyConfiguration failed: "
"%s (%d)\n", w32_strerror (ec), ec);
xfree (wurl);
return NULL;
}
defaultcfg = 1;
}
else
{
if (opt_verbose)
log_info ("WinHttpGetProxyForUrl failed: %s (%d)\n",
w32_strerror (ec), ec);
xfree (wurl);
return NULL;
}
}
xfree (wurl);
if (info.dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
{
result = wchar_to_utf8 (info.lpszProxy);
if (!result)
log_error ("wchar_to_utf8 failed: %s\n",
gpg_strerror (gpg_error_from_syserror ()));
else
{
if (opt_debug)
log_debug ("proxies to use: '%s'\n", result);
/* The returned proxies are delimited by whitespace or
* semicolons. We return only the first proxy. */
for (p=result; *p; p++)
if (spacep (p) || *p == ';')
{
*p = 0;
break;
}
}
}
else if (info.dwAccessType == WINHTTP_ACCESS_TYPE_NO_PROXY)
{
/* No proxy shall be used. */
}
else
log_error ("%s returned unexpected code %lu\n",
defaultcfg? "WinHttpGetDefaultProxyConfiguration"
:"WinHttpGetProxyForUrl", info.dwAccessType);
if (info.lpszProxy)
GlobalFree (info.lpszProxy);
if (info.lpszProxyBypass)
GlobalFree (info.lpszProxyBypass);
return result;
}
#endif /*HAVE_W32_SYSTEM*/
/* Return the proxy to be used for the URL or host specified in HD.
* If OVERRIDE_PROXY is not NULL and not empty, this proxy will be
* used instead of any configured or dynamically determined proxy. If
@ -1838,11 +1974,14 @@ release_proxy_info (proxy_info_t proxy)
static gpg_error_t
get_proxy_for_url (http_t hd, const char *override_proxy, proxy_info_t *r_proxy)
{
gpg_error_t err;
gpg_error_t err = 0;
const char *proxystr, *s;
proxy_info_t proxy;
#ifdef HAVE_W32_SYSTEM
char *proxystrbuf = NULL;
#endif
r_proxy = NULL;
*r_proxy = NULL;
if (override_proxy && *override_proxy)
proxystr = override_proxy;
@ -1851,6 +1990,9 @@ get_proxy_for_url (http_t hd, const char *override_proxy, proxy_info_t *r_proxy)
else if ((s = getenv (HTTP_PROXY_ENV)) && *s)
proxystr = s;
#ifdef HAVE_W32_SYSTEM
else if (hd->uri && hd->uri->original
&& (proxystrbuf = w32_get_proxy (hd->uri->original)))
proxystr = proxystrbuf;
#endif
else
return 0; /* No proxy known. */
@ -1860,7 +2002,7 @@ get_proxy_for_url (http_t hd, const char *override_proxy, proxy_info_t *r_proxy)
{
err = gpg_error_from_syserror ();
log_error ("error allocating memory for proxy\n");
return err;
goto leave;
}
err = parse_uri (&proxy->uri, proxystr, 0, 0);
@ -1901,6 +2043,10 @@ get_proxy_for_url (http_t hd, const char *override_proxy, proxy_info_t *r_proxy)
proxystr, hd->uri? hd->uri->original : NULL);
}
leave:
#ifdef HAVE_W32_SYSTEM
xfree (proxystrbuf);
#endif
if (err)
xfree (proxy);
else
@ -3938,3 +4084,13 @@ http_status2string (unsigned int status)
return "";
}
/* Fucntion called on SIGHUP to flush internal variables. */
void
http_reinitialize (void)
{
#ifdef HAVE_W32_SYSTEM
w32_get_internet_session (1); /* Clear our session. */
#endif /*HAVE_W32_SYSTEM*/
}

View File

@ -427,7 +427,9 @@ force the use of the default responder.
@item --honor-http-proxy
@opindex honor-http-proxy
If the environment variable @env{http_proxy} has been set, use its
value to access HTTP servers.
value to access HTTP servers. If on Windows the option is used but
the environment variable is not set, the proxy settings are taken
from the system.
@item --http-proxy @var{host}[:@var{port}]
@opindex http-proxy