diff options
author | Alberto Gonzalez Iniesta <agi@inittab.org> | 2012-11-05 16:28:09 +0100 |
---|---|---|
committer | Alberto Gonzalez Iniesta <agi@inittab.org> | 2012-11-05 16:28:09 +0100 |
commit | 8dd0350e1607aa30f7a043c8d5ec7a7eeb874115 (patch) | |
tree | 566d0620eb693320cb121dfd93a5675fa704a30b /proxy.c | |
parent | 349cfa7acb95abe865209a28e417ec74b56f9bba (diff) |
Imported Upstream version 2.3_rc1
Diffstat (limited to 'proxy.c')
-rw-r--r-- | proxy.c | 1129 |
1 files changed, 0 insertions, 1129 deletions
diff --git a/proxy.c b/proxy.c deleted file mode 100644 index fce64a1..0000000 --- a/proxy.c +++ /dev/null @@ -1,1129 +0,0 @@ -/* - * OpenVPN -- An application to securely tunnel IP networks - * over a single TCP/UDP port, with support for SSL/TLS-based - * session authentication and key exchange, - * packet encryption, packet authentication, and - * packet compression. - * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "syshead.h" - -#include "common.h" -#include "misc.h" -#include "crypto.h" -#include "win32.h" -#include "socket.h" -#include "fdmisc.h" -#include "proxy.h" -#include "base64.h" -#include "httpdigest.h" -#include "ntlm.h" - -#ifdef WIN32 -#include "ieproxy.h" -#endif - -#include "memdbg.h" - -#ifdef ENABLE_HTTP_PROXY - -#define UP_TYPE_PROXY "HTTP Proxy" - -/* cached proxy username/password */ -static struct user_pass static_proxy_user_pass; - -static bool -recv_line (socket_descriptor_t sd, - char *buf, - int len, - const int timeout_sec, - const bool verbose, - struct buffer *lookahead, - volatile int *signal_received) -{ - struct buffer la; - int lastc = 0; - - CLEAR (la); - if (lookahead) - la = *lookahead; - - while (true) - { - int status; - ssize_t size; - fd_set reads; - struct timeval tv; - uint8_t c; - - if (buf_defined (&la)) - { - ASSERT (buf_init (&la, 0)); - } - - FD_ZERO (&reads); - FD_SET (sd, &reads); - tv.tv_sec = timeout_sec; - tv.tv_usec = 0; - - status = select (sd + 1, &reads, NULL, NULL, &tv); - - get_signal (signal_received); - if (*signal_received) - goto error; - - /* timeout? */ - if (status == 0) - { - if (verbose) - msg (D_LINK_ERRORS | M_ERRNO_SOCK, "recv_line: TCP port read timeout expired"); - goto error; - } - - /* error */ - if (status < 0) - { - if (verbose) - msg (D_LINK_ERRORS | M_ERRNO_SOCK, "recv_line: TCP port read failed on select()"); - goto error; - } - - /* read single char */ - size = recv (sd, &c, 1, MSG_NOSIGNAL); - - /* error? */ - if (size != 1) - { - if (verbose) - msg (D_LINK_ERRORS | M_ERRNO_SOCK, "recv_line: TCP port read failed on recv()"); - goto error; - } - -#if 0 - if (isprint(c)) - msg (M_INFO, "PROXY: read '%c' (%d)", c, (int)c); - else - msg (M_INFO, "PROXY: read (%d)", (int)c); -#endif - - /* store char in buffer */ - if (len > 1) - { - *buf++ = c; - --len; - } - - /* also store char in lookahead buffer */ - if (buf_defined (&la)) - { - buf_write_u8 (&la, c); - if (!isprint(c) && !isspace(c)) /* not ascii? */ - { - if (verbose) - msg (D_LINK_ERRORS | M_ERRNO_SOCK, "recv_line: Non-ASCII character (%d) read on recv()", (int)c); - *lookahead = la; - return false; - } - } - - /* end of line? */ - if (lastc == '\r' && c == '\n') - break; - - lastc = c; - } - - /* append trailing null */ - if (len > 0) - *buf++ = '\0'; - - return true; - - error: - return false; -} - -static bool -send_line (socket_descriptor_t sd, - const char *buf) -{ - const ssize_t size = send (sd, buf, strlen (buf), MSG_NOSIGNAL); - if (size != (ssize_t) strlen (buf)) - { - msg (D_LINK_ERRORS | M_ERRNO_SOCK, "send_line: TCP port write failed on send()"); - return false; - } - return true; -} - -static bool -send_line_crlf (socket_descriptor_t sd, - const char *src) -{ - bool ret; - - struct buffer buf = alloc_buf (strlen (src) + 3); - ASSERT (buf_write (&buf, src, strlen (src))); - ASSERT (buf_write (&buf, "\r\n", 3)); - ret = send_line (sd, BSTR (&buf)); - free_buf (&buf); - return ret; -} - -static bool -send_crlf (socket_descriptor_t sd) -{ - return send_line_crlf (sd, ""); -} - -uint8_t * -make_base64_string2 (const uint8_t *str, int src_len, struct gc_arena *gc) -{ - uint8_t *ret = NULL; - char *b64out = NULL; - ASSERT (base64_encode ((const void *)str, src_len, &b64out) >= 0); - ret = (uint8_t *) string_alloc (b64out, gc); - free (b64out); - return ret; -} - -uint8_t * -make_base64_string (const uint8_t *str, struct gc_arena *gc) -{ - return make_base64_string2 (str, strlen ((const char *)str), gc); -} - -static const char * -username_password_as_base64 (const struct http_proxy_info *p, - struct gc_arena *gc) -{ - struct buffer out = alloc_buf_gc (strlen (p->up.username) + strlen (p->up.password) + 2, gc); - ASSERT (strlen (p->up.username) > 0); - buf_printf (&out, "%s:%s", p->up.username, p->up.password); - return (const char *)make_base64_string ((const uint8_t*)BSTR (&out), gc); -} - -static void -get_user_pass_http (struct http_proxy_info *p, const bool force) -{ - if (!static_proxy_user_pass.defined || force) - { - unsigned int flags = GET_USER_PASS_MANAGEMENT; - if (p->queried_creds) - flags |= GET_USER_PASS_PREVIOUS_CREDS_FAILED; - get_user_pass (&static_proxy_user_pass, - p->options.auth_file, - UP_TYPE_PROXY, - flags); - p->queried_creds = true; - p->up = static_proxy_user_pass; - } -} -static void -clear_user_pass_http (void) -{ - purge_user_pass (&static_proxy_user_pass, true); -} - -static void -dump_residual (socket_descriptor_t sd, - int timeout, - volatile int *signal_received) -{ - char buf[256]; - while (true) - { - if (!recv_line (sd, buf, sizeof (buf), timeout, true, NULL, signal_received)) - return; - chomp (buf); - msg (D_PROXY, "PROXY HEADER: '%s'", buf); - } -} - -/* - * Extract the Proxy-Authenticate header from the stream. - * Consumes all headers. - */ -static int -get_proxy_authenticate (socket_descriptor_t sd, - int timeout, - char **data, - struct gc_arena *gc, - volatile int *signal_received) -{ - char buf[256]; - int ret = HTTP_AUTH_NONE; - while (true) - { - if (!recv_line (sd, buf, sizeof (buf), timeout, true, NULL, signal_received)) - { - *data = NULL; - return HTTP_AUTH_NONE; - } - chomp (buf); - if (!strlen(buf)) - return ret; - if (ret == HTTP_AUTH_NONE && !strncmp(buf, "Proxy-Authenticate: ", 20)) - { - if (!strncmp(buf+20, "Basic ", 6)) - { - msg (D_PROXY, "PROXY AUTH BASIC: '%s'", buf); - *data = string_alloc(buf+26, gc); - ret = HTTP_AUTH_BASIC; - } -#if PROXY_DIGEST_AUTH - else if (!strncmp(buf+20, "Digest ", 7)) - { - msg (D_PROXY, "PROXY AUTH DIGEST: '%s'", buf); - *data = string_alloc(buf+27, gc); - ret = HTTP_AUTH_DIGEST; - } -#endif -#if NTLM - else if (!strncmp(buf+20, "NTLM", 4)) - { - msg (D_PROXY, "PROXY AUTH HTLM: '%s'", buf); - *data = NULL; - ret = HTTP_AUTH_NTLM; - } -#endif - } - } -} - -static void -store_proxy_authenticate (struct http_proxy_info *p, char *data) -{ - if (p->proxy_authenticate) - free (p->proxy_authenticate); - p->proxy_authenticate = data; -} - -/* - * Parse out key/value pairs from Proxy-Authenticate string. - * Return true on success, or false on parse failure. - */ -static bool -get_key_value(const char *str, /* source string */ - char *key, /* key stored here */ - char *value, /* value stored here */ - int max_key_len, - int max_value_len, - const char **endptr) /* next search position */ -{ - int c; - bool starts_with_quote = false; - bool escape = false; - - for (c = max_key_len-1; (*str && (*str != '=') && c--); ) - *key++ = *str++; - *key = '\0'; - - if('=' != *str++) - /* no key/value found */ - return false; - - if('\"' == *str) - { - /* quoted string */ - str++; - starts_with_quote = true; - } - - for (c = max_value_len-1; *str && c--; str++) - { - switch (*str) - { - case '\\': - if (!escape) - { - /* possibly the start of an escaped quote */ - escape = true; - *value++ = '\\'; /* even though this is an escape character, we still - store it as-is in the target buffer */ - continue; - } - break; - case ',': - if (!starts_with_quote) - { - /* this signals the end of the value if we didn't get a starting quote - and then we do "sloppy" parsing */ - c=0; /* the end */ - continue; - } - break; - case '\r': - case '\n': - /* end of string */ - c=0; - continue; - case '\"': - if (!escape && starts_with_quote) - { - /* end of string */ - c=0; - continue; - } - break; - } - escape = false; - *value++ = *str; - } - *value = '\0'; - - *endptr = str; - - return true; /* success */ -} - -static char * -get_pa_var (const char *key, const char *pa, struct gc_arena *gc) -{ - char k[64]; - char v[256]; - const char *content = pa; - - while (true) - { - const int status = get_key_value(content, k, v, sizeof(k), sizeof(v), &content); - if (status) - { - if (!strcmp(key, k)) - return string_alloc(v, gc); - } - else - return NULL; - - /* advance to start of next key */ - if (*content == ',') - ++content; - while (*content && isspace(*content)) - ++content; - } -} - -struct http_proxy_info * -http_proxy_new (const struct http_proxy_options *o, - struct auto_proxy_info *auto_proxy_info) -{ - struct http_proxy_info *p; - struct http_proxy_options opt; - - if (auto_proxy_info) - { - if (o && o->server) - { - /* if --http-proxy explicitly given, disable auto-proxy */ - auto_proxy_info = NULL; - } - else - { - /* if no --http-proxy explicitly given and no auto settings, fail */ - if (!auto_proxy_info->http.server) - return NULL; - - if (o) - { - opt = *o; - } - else - { - CLEAR (opt); - - /* These settings are only used for --auto-proxy */ - opt.timeout = 5; - opt.http_version = "1.0"; - } - - opt.server = auto_proxy_info->http.server; - opt.port = auto_proxy_info->http.port; - if (!opt.auth_retry) - opt.auth_retry = PAR_ALL; - - o = &opt; - } - } - - if (!o || !o->server) - msg (M_FATAL, "HTTP_PROXY: server not specified"); - - ASSERT (legal_ipv4_port (o->port)); - - ALLOC_OBJ_CLEAR (p, struct http_proxy_info); - p->options = *o; - - /* parse authentication method */ - p->auth_method = HTTP_AUTH_NONE; - if (o->auth_method_string) - { - if (!strcmp (o->auth_method_string, "none")) - p->auth_method = HTTP_AUTH_NONE; - else if (!strcmp (o->auth_method_string, "basic")) - p->auth_method = HTTP_AUTH_BASIC; -#if NTLM - else if (!strcmp (o->auth_method_string, "ntlm")) - p->auth_method = HTTP_AUTH_NTLM; - else if (!strcmp (o->auth_method_string, "ntlm2")) - p->auth_method = HTTP_AUTH_NTLM2; -#endif - else - msg (M_FATAL, "ERROR: unknown HTTP authentication method: '%s'", - o->auth_method_string); - } - - /* only basic and NTLM/NTLMv2 authentication supported so far */ - if (p->auth_method == HTTP_AUTH_BASIC || p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) - { - get_user_pass_http (p, true); - } - -#if !NTLM - if (p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) - msg (M_FATAL, "Sorry, this version of " PACKAGE_NAME " was built without NTLM Proxy support."); -#endif - - p->defined = true; - return p; -} - -void -http_proxy_close (struct http_proxy_info *hp) -{ - free (hp); -} - -bool -establish_http_proxy_passthru (struct http_proxy_info *p, - socket_descriptor_t sd, /* already open to proxy */ - const char *host, /* openvpn server remote */ - const int port, /* openvpn server port */ - struct buffer *lookahead, - volatile int *signal_received) -{ - struct gc_arena gc = gc_new (); - char buf[512]; - char buf2[128]; - char get[80]; - int status; - int nparms; - bool ret = false; - bool processed = false; - - /* get user/pass if not previously given or if --auto-proxy is being used */ - if (p->auth_method == HTTP_AUTH_BASIC - || p->auth_method == HTTP_AUTH_DIGEST - || p->auth_method == HTTP_AUTH_NTLM) - get_user_pass_http (p, false); - - /* are we being called again after getting the digest server nonce in the previous transaction? */ - if (p->auth_method == HTTP_AUTH_DIGEST && p->proxy_authenticate) - { - nparms = 1; - status = 407; - } - else - { - /* format HTTP CONNECT message */ - openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s", - host, - port, - p->options.http_version); - - msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); - - /* send HTTP CONNECT message to proxy */ - if (!send_line_crlf (sd, buf)) - goto error; - - openvpn_snprintf(buf, sizeof(buf), "Host: %s", host); - if (!send_line_crlf(sd, buf)) - goto error; - - /* send User-Agent string if provided */ - if (p->options.user_agent) - { - openvpn_snprintf (buf, sizeof(buf), "User-Agent: %s", - p->options.user_agent); - if (!send_line_crlf (sd, buf)) - goto error; - } - - /* auth specified? */ - switch (p->auth_method) - { - case HTTP_AUTH_NONE: - break; - - case HTTP_AUTH_BASIC: - openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: Basic %s", - username_password_as_base64 (p, &gc)); - msg (D_PROXY, "Attempting Basic Proxy-Authorization"); - dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); - if (!send_line_crlf (sd, buf)) - goto error; - break; - -#if NTLM - case HTTP_AUTH_NTLM: - case HTTP_AUTH_NTLM2: - /* keep-alive connection */ - openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive"); - if (!send_line_crlf (sd, buf)) - goto error; - - openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s", - ntlm_phase_1 (p, &gc)); - msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 1"); - dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); - if (!send_line_crlf (sd, buf)) - goto error; - break; -#endif - - default: - ASSERT (0); - } - - /* send empty CR, LF */ - if (!send_crlf (sd)) - goto error; - - /* receive reply from proxy */ - if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) - goto error; - - /* remove trailing CR, LF */ - chomp (buf); - - msg (D_PROXY, "HTTP proxy returned: '%s'", buf); - - /* parse return string */ - nparms = sscanf (buf, "%*s %d", &status); - - } - - /* check for a "407 Proxy Authentication Required" response */ - while (nparms >= 1 && status == 407) - { - msg (D_PROXY, "Proxy requires authentication"); - - if (p->auth_method == HTTP_AUTH_BASIC && !processed) - { - processed = true; - } - else if ((p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) && !processed) /* check for NTLM */ - { -#if NTLM - /* look for the phase 2 response */ - - while (true) - { - if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) - goto error; - chomp (buf); - msg (D_PROXY, "HTTP proxy returned: '%s'", buf); - - openvpn_snprintf (get, sizeof get, "%%*s NTLM %%%ds", (int) sizeof (buf2) - 1); - nparms = sscanf (buf, get, buf2); - buf2[127] = 0; /* we only need the beginning - ensure it's null terminated. */ - - /* check for "Proxy-Authenticate: NTLM TlRM..." */ - if (nparms == 1) - { - /* parse buf2 */ - msg (D_PROXY, "auth string: '%s'", buf2); - break; - } - } - /* if we are here then auth string was got */ - msg (D_PROXY, "Received NTLM Proxy-Authorization phase 2 response"); - - /* receive and discard everything else */ - while (recv_line (sd, NULL, 0, 2, true, NULL, signal_received)) - ; - - /* now send the phase 3 reply */ - - /* format HTTP CONNECT message */ - openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s", - host, - port, - p->options.http_version); - - msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); - - /* send HTTP CONNECT message to proxy */ - if (!send_line_crlf (sd, buf)) - goto error; - - /* keep-alive connection */ - openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive"); - if (!send_line_crlf (sd, buf)) - goto error; - - - /* send HOST etc, */ - openvpn_snprintf (buf, sizeof(buf), "Host: %s", host); - msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); - if (!send_line_crlf (sd, buf)) - goto error; - - msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 3"); - { - const char *np3 = ntlm_phase_3 (p, buf2, &gc); - if (!np3) - { - msg (D_PROXY, "NTLM Proxy-Authorization phase 3 failed: received corrupted data from proxy server"); - goto error; - } - openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s", np3); - } - - msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); - if (!send_line_crlf (sd, buf)) - goto error; - /* ok so far... */ - /* send empty CR, LF */ - if (!send_crlf (sd)) - goto error; - - /* receive reply from proxy */ - if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) - goto error; - - /* remove trailing CR, LF */ - chomp (buf); - - msg (D_PROXY, "HTTP proxy returned: '%s'", buf); - - /* parse return string */ - nparms = sscanf (buf, "%*s %d", &status); - processed = true; -#endif - } -#if PROXY_DIGEST_AUTH - else if (p->auth_method == HTTP_AUTH_DIGEST && !processed) - { - char *pa = p->proxy_authenticate; - const int method = p->auth_method; - ASSERT(pa); - - if (method == HTTP_AUTH_DIGEST) - { - const char *http_method = "CONNECT"; - const char *nonce_count = "00000001"; - const char *qop = "auth"; - const char *username = p->up.username; - const char *password = p->up.password; - char *opaque_kv = ""; - char uri[128]; - uint8_t cnonce_raw[8]; - uint8_t *cnonce; - HASHHEX session_key; - HASHHEX response; - - const char *realm = get_pa_var("realm", pa, &gc); - const char *nonce = get_pa_var("nonce", pa, &gc); - const char *algor = get_pa_var("algorithm", pa, &gc); - const char *opaque = get_pa_var("opaque", pa, &gc); - - /* generate a client nonce */ - ASSERT(RAND_bytes(cnonce_raw, sizeof(cnonce_raw))); - cnonce = make_base64_string2(cnonce_raw, sizeof(cnonce_raw), &gc); - - - /* build the digest response */ - openvpn_snprintf (uri, sizeof(uri), "%s:%d", - host, - port); - - if (opaque) - { - const int len = strlen(opaque)+16; - opaque_kv = gc_malloc(len, false, &gc); - openvpn_snprintf (opaque_kv, len, ", opaque=\"%s\"", opaque); - } - - DigestCalcHA1(algor, - username, - realm, - password, - nonce, - (char *)cnonce, - session_key); - DigestCalcResponse(session_key, - nonce, - nonce_count, - (char *)cnonce, - qop, - http_method, - uri, - NULL, - response); - - /* format HTTP CONNECT message */ - openvpn_snprintf (buf, sizeof(buf), "%s %s HTTP/%s", - http_method, - uri, - p->options.http_version); - - msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); - - /* send HTTP CONNECT message to proxy */ - if (!send_line_crlf (sd, buf)) - goto error; - - /* send HOST etc, */ - openvpn_snprintf (buf, sizeof(buf), "Host: %s", host); - msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); - if (!send_line_crlf (sd, buf)) - goto error; - - /* send digest response */ - openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", qop=%s, nc=%s, cnonce=\"%s\", response=\"%s\"%s", - username, - realm, - nonce, - uri, - qop, - nonce_count, - cnonce, - response, - opaque_kv - ); - msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); - if (!send_line_crlf (sd, buf)) - goto error; - if (!send_crlf (sd)) - goto error; - - /* receive reply from proxy */ - if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) - goto error; - - /* remove trailing CR, LF */ - chomp (buf); - - msg (D_PROXY, "HTTP proxy returned: '%s'", buf); - - /* parse return string */ - nparms = sscanf (buf, "%*s %d", &status); - processed = true; - } - else - { - msg (D_PROXY, "HTTP proxy: digest method not supported"); - goto error; - } - } -#endif - else if (p->options.auth_retry) - { - /* figure out what kind of authentication the proxy needs */ - char *pa = NULL; - const int method = get_proxy_authenticate(sd, - p->options.timeout, - &pa, - NULL, - signal_received); - if (method != HTTP_AUTH_NONE) - { - if (pa) - msg (D_PROXY, "HTTP proxy authenticate '%s'", pa); - if (p->options.auth_retry == PAR_NCT && method == HTTP_AUTH_BASIC) - { - msg (D_PROXY, "HTTP proxy: support for basic auth and other cleartext proxy auth methods is disabled"); - goto error; - } - p->auth_method = method; - store_proxy_authenticate(p, pa); - ret = true; - goto done; - } - else - { - msg (D_PROXY, "HTTP proxy: do not recognize the authentication method required by proxy"); - free (pa); - goto error; - } - } - else - { - if (!processed) - msg (D_PROXY, "HTTP proxy: no support for proxy authentication method"); - goto error; - } - - /* clear state */ - if (p->options.auth_retry) - clear_user_pass_http(); - store_proxy_authenticate(p, NULL); - } - - /* check return code, success = 200 */ - if (nparms < 1 || status != 200) - { - msg (D_LINK_ERRORS, "HTTP proxy returned bad status"); -#if 0 - /* DEBUGGING -- show a multi-line HTTP error response */ - dump_residual(sd, p->options.timeout, signal_received); -#endif - goto error; - } - - /* SUCCESS */ - - /* receive line from proxy and discard */ - if (!recv_line (sd, NULL, 0, p->options.timeout, true, NULL, signal_received)) - goto error; - - /* - * Toss out any extraneous chars, but don't throw away the - * start of the OpenVPN data stream (put it in lookahead). - */ - while (recv_line (sd, NULL, 0, 2, false, lookahead, signal_received)) - ; - - /* reset queried_creds so that we don't think that the next creds request is due to an auth error */ - p->queried_creds = false; - -#if 0 - if (lookahead && BLEN (lookahead)) - msg (M_INFO, "HTTP PROXY: lookahead: %s", format_hex (BPTR (lookahead), BLEN (lookahead), 0)); -#endif - - done: - gc_free (&gc); - return ret; - - error: - /* on error, should we exit or restart? */ - if (!*signal_received) - *signal_received = (p->options.retry ? SIGUSR1 : SIGTERM); /* SOFT-SIGUSR1 -- HTTP proxy error */ - gc_free (&gc); - return ret; -} - -#else -static void dummy(void) {} -#endif /* ENABLE_HTTP_PROXY */ - -#ifdef GENERAL_PROXY_SUPPORT - -#ifdef WIN32 - -#if 0 -char * -get_windows_internet_string (const DWORD dwOption, struct gc_arena *gc) -{ - DWORD size = 0; - char *ret = NULL; - - /* Initially, get size of return buffer */ - InternetQueryOption (NULL, dwOption, NULL, &size); - if (size) - { - /* Now get actual info */ - ret = (INTERNET_PROXY_INFO *) gc_malloc (size, false, gc); - if (!InternetQueryOption (NULL, dwOption, (LPVOID) ret, &size)) - ret = NULL; - } - return ret; -} -#endif - -static INTERNET_PROXY_INFO * -get_windows_proxy_settings (struct gc_arena *gc) -{ - DWORD size = 0; - INTERNET_PROXY_INFO *ret = NULL; - - /* Initially, get size of return buffer */ - InternetQueryOption (NULL, INTERNET_OPTION_PROXY, NULL, &size); - if (size) - { - /* Now get actual info */ - ret = (INTERNET_PROXY_INFO *) gc_malloc (size, false, gc); - if (!InternetQueryOption (NULL, INTERNET_OPTION_PROXY, (LPVOID) ret, &size)) - ret = NULL; - } - return ret; -} - -static const char * -parse_windows_proxy_setting (const char *str, struct auto_proxy_info_entry *e, struct gc_arena *gc) -{ - char buf[128]; - const char *ret = NULL; - struct buffer in; - - CLEAR (*e); - - buf_set_read (&in, (const uint8_t *)str, strlen (str)); - - if (strchr (str, '=') != NULL) - { - if (buf_parse (&in, '=', buf, sizeof (buf))) - ret = string_alloc (buf, gc); - } - - if (buf_parse (&in, ':', buf, sizeof (buf))) - e->server = string_alloc (buf, gc); - - if (e->server && buf_parse (&in, '\0', buf, sizeof (buf))) - e->port = atoi (buf); - - return ret; -} - -static void -parse_windows_proxy_setting_list (const char *str, const char *type, struct auto_proxy_info_entry *e, struct gc_arena *gc) -{ - struct gc_arena gc_local = gc_new (); - struct auto_proxy_info_entry el; - - CLEAR (*e); - if (type) - { - char buf[128]; - struct buffer in; - - buf_set_read (&in, (const uint8_t *)str, strlen (str)); - if (strchr (str, '=') != NULL) - { - while (buf_parse (&in, ' ', buf, sizeof (buf))) - { - const char *t = parse_windows_proxy_setting (buf, &el, &gc_local); - if (t && !strcmp (t, type)) - goto found; - } - } - } - else - { - if (!parse_windows_proxy_setting (str, &el, &gc_local)) - goto found; - } - goto done; - - found: - if (el.server && el.port > 0) - { - e->server = string_alloc (el.server, gc); - e->port = el.port; - } - - done: - gc_free (&gc_local); -} - -static const char * -win_proxy_access_type (const DWORD dwAccessType) -{ - switch (dwAccessType) - { - case INTERNET_OPEN_TYPE_DIRECT: - return "INTERNET_OPEN_TYPE_DIRECT"; - case INTERNET_OPEN_TYPE_PROXY: - return "INTERNET_OPEN_TYPE_PROXY"; - default: - return "[UNKNOWN]"; - } -} - -void -show_win_proxy_settings (const int msglevel) -{ - INTERNET_PROXY_INFO *info; - struct gc_arena gc = gc_new (); - - info = get_windows_proxy_settings (&gc); - msg (msglevel, "PROXY INFO: %s %s", - win_proxy_access_type (info->dwAccessType), - info->lpszProxy ? info->lpszProxy : "[NULL]"); - - gc_free (&gc); -} - -struct auto_proxy_info * -get_proxy_settings (char **err, struct gc_arena *gc) -{ - struct gc_arena gc_local = gc_new (); - INTERNET_PROXY_INFO *info; - struct auto_proxy_info *pi; - - ALLOC_OBJ_CLEAR_GC (pi, struct auto_proxy_info, gc); - - if (err) - *err = NULL; - - info = get_windows_proxy_settings (&gc_local); - - if (!info) - { - if (err) - *err = "PROXY: failed to obtain windows proxy info"; - goto done; - } - - switch (info->dwAccessType) - { - case INTERNET_OPEN_TYPE_DIRECT: - break; - case INTERNET_OPEN_TYPE_PROXY: - if (!info->lpszProxy) - break; - parse_windows_proxy_setting_list (info->lpszProxy, NULL, &pi->http, gc); - if (!pi->http.server) - parse_windows_proxy_setting_list (info->lpszProxy, "http", &pi->http, gc); - parse_windows_proxy_setting_list (info->lpszProxy, "socks", &pi->socks, gc); - break; - default: - if (err) - *err = "PROXY: unknown proxy type"; - break; - } - - done: - gc_free (&gc_local); - return pi; -} - -#else - -struct auto_proxy_info * -get_proxy_settings (char **err, struct gc_arena *gc) -{ -#if 1 - if (err) - *err = string_alloc ("PROXY: automatic detection not supported on this OS", gc); - return NULL; -#else /* test --auto-proxy feature */ - struct auto_proxy_info *pi; - ALLOC_OBJ_CLEAR_GC (pi, struct auto_proxy_info, gc); - pi->http.server = "10.10.0.2"; - pi->http.port = 4000; - return pi; -#endif -} - -#endif - -#endif /* GENERAL_PROXY_SUPPORT */ |