42#define UP_TYPE_PROXY "HTTP Proxy"
51 (*hpo)->http_version =
"1.0";
62 struct buffer *lookahead,
volatile int *signal_received)
88 tv.tv_sec = timeout_sec;
91 status = select(sd + 1, &reads, NULL, NULL, &tv);
135 msg(
M_INFO,
"PROXY: read '%c' (%d)", c, (
int)c);
154 if (!isprint(c) && !isspace(c))
159 "recv_line: Non-ASCII character (%d) read on recv()", (
int)c);
167 if (lastc ==
'\r' && c ==
'\n')
190 const ssize_t size = send(sd, buf, strlen(buf),
MSG_NOSIGNAL);
191 if (size != (ssize_t)strlen(buf))
240 buf_printf(&out,
"%s:%s",
p->up.username,
p->up.password);
267 const char *auth_file =
p->options.auth_file;
268 if (
p->options.auth_file_up)
270 auth_file =
p->options.auth_file_up;
276 if (
p->options.inline_creds)
288 p->queried_creds =
true;
297 volatile int *signal_received)
302 if (!
recv_line(sd, buf,
sizeof(buf), timeout,
true,
NULL, signal_received))
318 volatile int *signal_received)
324 if (!
recv_line(sd, buf,
sizeof(buf), timeout,
true,
NULL, signal_received))
337 if (!
strncmp(buf + 20,
"Basic ", 6))
344 else if (!
strncmp(buf + 20,
"Digest ", 7))
352 else if (!
strncmp(buf + 20,
"NTLM", 4))
366 free(
p->proxy_authenticate);
367 p->proxy_authenticate =
data;
458 const char *content =
pa;
480 while (*content &&
isspace(*content))
494 msg(
M_FATAL,
"HTTP_PROXY: server not specified");
518 "NTLM v1 authentication has been removed in OpenVPN 2.7. Will try to use NTLM v2 authentication.");
544 "Sorry, this version of " PACKAGE_NAME
" was built without NTLM Proxy support.");
565 bool host_header_sent =
false;
580 host_header_sent =
true;
588 host_header_sent =
true;
592 msg(
D_PROXY,
"Send to HTTP proxy: '%s'", buf);
599 if (!host_header_sent)
601 snprintf(buf,
sizeof(buf),
"Host: %s", host);
602 msg(
D_PROXY,
"Send to HTTP proxy: '%s'", buf);
613 msg(
D_PROXY,
"Send to HTTP proxy: '%s'", buf);
637 bool processed =
false;
665 msg(
D_PROXY,
"Send to HTTP proxy: '%s'", buf);
685 snprintf(buf,
sizeof(buf),
"Proxy-Authorization: Basic %s",
687 msg(
D_PROXY,
"Attempting Basic Proxy-Authorization");
698 snprintf(buf,
sizeof(buf),
"Proxy-Connection: Keep-Alive");
704 snprintf(buf,
sizeof(buf),
"Proxy-Authorization: NTLM %s",
ntlm_phase_1(p, &
gc));
705 msg(
D_PROXY,
"Attempting NTLM Proxy-Authorization phase 1");
729 true, NULL, signal_received))
737 msg(
D_PROXY,
"HTTP proxy returned: '%s'", buf);
740 nparms = sscanf(buf,
"%*s %d", &
status);
744 while (nparms >= 1 &&
status == 407)
746 msg(
D_PROXY,
"Proxy requires authentication");
766 msg(
D_PROXY,
"HTTP proxy returned: '%s'", buf);
770 snprintf(get,
sizeof(get),
"%%*s NTLM %%%zus",
sizeof(buf2) - 1);
771 nparms = sscanf(buf, get, buf2);
782 msg(
D_PROXY,
"Received NTLM Proxy-Authorization phase 2 response");
785 while (
recv_line(sd, NULL, 0, 2,
true, NULL, signal_received))
792 snprintf(buf,
sizeof(buf),
"CONNECT %s:%s HTTP/%s", host, port,
795 msg(
D_PROXY,
"Send to HTTP proxy: '%s'", buf);
804 snprintf(buf,
sizeof(buf),
"Proxy-Connection: Keep-Alive");
816 msg(
D_PROXY,
"Attempting NTLM Proxy-Authorization phase 3");
822 "NTLM Proxy-Authorization phase 3 failed: received corrupted data from proxy server");
825 snprintf(buf,
sizeof(buf),
"Proxy-Authorization: NTLM %s", np3);
828 msg(
D_PROXY,
"Send to HTTP proxy: '%s'", buf);
851 msg(
D_PROXY,
"HTTP proxy returned: '%s'", buf);
854 nparms = sscanf(buf,
"%*s %d", &
status);
867 const char *http_method =
"CONNECT";
868 const char *nonce_count =
"00000001";
869 const char *qop =
"auth";
872 char *opaque_kv =
"";
874 uint8_t cnonce_raw[8];
884 if (!realm || !nonce)
887 "from server: realm= or nonce= missing");
897 snprintf(uri,
sizeof(uri),
"%s:%s", host, port);
901 const int len = strlen(opaque) + 16;
903 snprintf(opaque_kv, len,
", opaque=\"%s\"", opaque);
906 DigestCalcHA1(algor, username, realm, password, nonce, (
char *)cnonce, session_key);
908 http_method, uri, NULL, response);
911 snprintf(buf,
sizeof(buf),
"%s %s HTTP/%s", http_method, uri,
914 msg(
D_PROXY,
"Send to HTTP proxy: '%s'", buf);
931 "Proxy-Authorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", qop=%s, nc=%s, cnonce=\"%s\", response=\"%s\"%s",
932 username, realm, nonce, uri, qop, nonce_count, cnonce, response, opaque_kv);
933 if (sret >=
sizeof(buf))
938 msg(
D_PROXY,
"Send to HTTP proxy: '%s'", buf);
961 msg(
D_PROXY,
"HTTP proxy returned: '%s'", buf);
964 nparms = sscanf(buf,
"%*s %d", &
status);
969 msg(
D_PROXY,
"HTTP proxy: digest method not supported");
984 msg(
D_PROXY,
"HTTP proxy authenticate '%s'", pa);
989 "HTTP proxy: support for basic auth and other cleartext proxy auth methods is disabled");
1001 "HTTP proxy: do not recognize the authentication method required by proxy");
1010 msg(
D_PROXY,
"HTTP proxy: no support for proxy authentication method");
1017 if (nparms < 1 ||
status != 200)
1040 while (
recv_line(sd, NULL, 0, 2,
false, lookahead, signal_received))
1049 if (lookahead &&
BLEN(lookahead))
void free_buf(struct buffer *buf)
bool buf_printf(struct buffer *buf, const char *format,...)
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
struct buffer alloc_buf(size_t size)
char * string_alloc(const char *str, struct gc_arena *gc)
static char * format_hex(const uint8_t *data, int size, int maxoutput, struct gc_arena *gc)
static void secure_memzero(void *data, size_t len)
Securely zeroise memory.
static bool buf_write(struct buffer *dest, const void *src, size_t size)
static bool buf_write_u8(struct buffer *dest, uint8_t data)
#define ALLOC_OBJ_CLEAR_GC(dptr, type, gc)
static void gc_free(struct gc_arena *a)
#define ALLOC_OBJ_CLEAR(dptr, type)
static bool buf_defined(const struct buffer *buf)
#define buf_init(buf, offset)
static struct gc_arena gc_new(void)
Data Channel Cryptography Module.
int rand_bytes(uint8_t *output, int len)
Wrapper for secure random number generator.
static void openvpn_fd_set(socket_descriptor_t fd, fd_set *setp)
int get_server_poll_remaining_time(struct event_timeout *server_poll_timeout)
Interface functions to the internal and external multiplexers.
void DigestCalcHA1(IN char *pszAlg, IN char *pszUserName, IN char *pszRealm, IN char *pszPassword, IN char *pszNonce, IN char *pszCNonce, OUT HASHHEX SessionKey)
void DigestCalcResponse(IN HASHHEX HA1, IN char *pszNonce, IN char *pszNonceCount, IN char *pszCNonce, IN char *pszQop, IN char *pszMethod, IN char *pszDigestUri, IN HASHHEX HEntity, OUT HASHHEX Response)
static SERVICE_STATUS status
void unprotect_user_pass(struct user_pass *up)
Decrypt username and password buffers in user_pass.
void purge_user_pass(struct user_pass *up, const bool force)
void protect_user_pass(struct user_pass *up)
Encrypt username and password buffers in user_pass.
#define GET_USER_PASS_MANAGEMENT
#define GET_USER_PASS_INLINE_CREDS
indicates that auth_file is actually inline creds
static bool get_user_pass(struct user_pass *up, const char *auth_file, const char *prefix, const unsigned int flags)
Retrieves the user credentials from various sources depending on the flags.
#define GET_USER_PASS_PREVIOUS_CREDS_FAILED
const char * ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_arena *gc)
const char * ntlm_phase_1(const struct http_proxy_info *p, struct gc_arena *gc)
static bool send_crlf(socket_descriptor_t sd)
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)
void http_proxy_close(struct http_proxy_info *hp)
static void clear_user_pass_http(void)
static char * get_pa_var(const char *key, const char *pa, struct gc_arena *gc)
static const char * username_password_as_base64(const struct http_proxy_info *p, struct gc_arena *gc)
struct http_proxy_info * http_proxy_new(const struct http_proxy_options *o)
struct http_proxy_options * init_http_proxy_options_once(struct http_proxy_options **hpo, struct gc_arena *gc)
static void store_proxy_authenticate(struct http_proxy_info *p, char *data)
static bool get_key_value(const char *str, char *key, char *value, int max_key_len, int max_value_len, const char **endptr)
bool establish_http_proxy_passthru(struct http_proxy_info *p, socket_descriptor_t sd, const char *host, const char *port, struct event_timeout *server_poll_timeout, struct buffer *lookahead, struct signal_info *sig_info)
static bool send_line(socket_descriptor_t sd, const char *buf)
static bool send_line_crlf(socket_descriptor_t sd, const char *src)
static void get_user_pass_http(struct http_proxy_info *p, const bool force)
uint8_t * make_base64_string2(const uint8_t *str, int src_len, struct gc_arena *gc)
uint8_t * make_base64_string(const uint8_t *str, struct gc_arena *gc)
static bool add_proxy_headers(struct http_proxy_info *p, socket_descriptor_t sd, const char *host)
static int get_proxy_authenticate(socket_descriptor_t sd, int timeout, char **data, volatile int *signal_received)
#define MAX_CUSTOM_HTTP_HEADER
void register_signal(struct signal_info *si, int signum, const char *signal_text)
Register a soft signal in the signal_info struct si respecting priority.
static void get_signal(volatile int *sig)
Copy the global signal_received (if non-zero) to the passed-in argument sig.
int openvpn_base64_encode(const void *data, int size, char **str)
Wrapper structure for dynamically allocated memory.
uint8_t * data
Pointer to the allocated memory.
int len
Length in bytes of the actual content within the allocated memory.
Garbage collection arena used to keep track of dynamically allocated memory.
char * proxy_authenticate
struct http_proxy_options options
const char * http_version
const char * auth_method_string
struct http_custom_header custom_headers[MAX_CUSTOM_HTTP_HEADER]
Container for unidirectional cipher and HMAC key material.
volatile int signal_received
char password[USER_PASS_LEN]
char username[USER_PASS_LEN]
SOCKET socket_descriptor_t