OpenVPN
proxy.c
Go to the documentation of this file.
1/*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
7 *
8 * Copyright (C) 2002-2025 OpenVPN Inc <sales@openvpn.net>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, see <https://www.gnu.org/licenses/>.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include "syshead.h"
28
29#include "common.h"
30#include "misc.h"
31#include "crypto.h"
32#include "win32.h"
33#include "socket.h"
34#include "fdmisc.h"
35#include "proxy.h"
36#include "base64.h"
37#include "httpdigest.h"
38#include "ntlm.h"
39#include "memdbg.h"
40#include "forward.h"
41
42#define UP_TYPE_PROXY "HTTP Proxy"
43
44struct http_proxy_options *
46{
47 if (!*hpo)
48 {
50 /* http proxy defaults */
51 (*hpo)->http_version = "1.0";
52 }
53 return *hpo;
54}
55
56
57#if defined(__GNUC__) || defined(__clang__)
58#pragma GCC diagnostic push
59#pragma GCC diagnostic ignored "-Wconversion"
60#endif
61
62/* cached proxy username/password */
64
65static bool
66recv_line(socket_descriptor_t sd, char *buf, int len, const int timeout_sec, const bool verbose,
67 struct buffer *lookahead, volatile int *signal_received)
68{
69 struct buffer la;
70 int lastc = 0;
71
72 CLEAR(la);
73 if (lookahead)
74 {
75 la = *lookahead;
76 }
77
78 while (true)
79 {
80 int status;
81 ssize_t size;
82 fd_set reads;
83 struct timeval tv;
84 uint8_t c;
85
86 if (buf_defined(&la))
87 {
88 ASSERT(buf_init(&la, 0));
89 }
90
91 FD_ZERO(&reads);
92 openvpn_fd_set(sd, &reads);
93 tv.tv_sec = timeout_sec;
94 tv.tv_usec = 0;
95
96 status = select(sd + 1, &reads, NULL, NULL, &tv);
97
98 get_signal(signal_received);
99 if (*signal_received)
100 {
101 goto error;
102 }
103
104 /* timeout? */
105 if (status == 0)
106 {
107 if (verbose)
108 {
109 msg(D_LINK_ERRORS | M_ERRNO, "recv_line: TCP port read timeout expired");
110 }
111 goto error;
112 }
113
114 /* error */
115 if (status < 0)
116 {
117 if (verbose)
118 {
119 msg(D_LINK_ERRORS | M_ERRNO, "recv_line: TCP port read failed on select()");
120 }
121 goto error;
122 }
123
124 /* read single char */
125 size = recv(sd, (void *)&c, 1, MSG_NOSIGNAL);
126
127 /* error? */
128 if (size != 1)
129 {
130 if (verbose)
131 {
132 msg(D_LINK_ERRORS | M_ERRNO, "recv_line: TCP port read failed on recv()");
133 }
134 goto error;
135 }
136
137#if 0
138 if (isprint(c))
139 {
140 msg(M_INFO, "PROXY: read '%c' (%d)", c, (int)c);
141 }
142 else
143 {
144 msg(M_INFO, "PROXY: read (%d)", (int)c);
145 }
146#endif
147
148 /* store char in buffer */
149 if (len > 1)
150 {
151 *buf++ = c;
152 --len;
153 }
154
155 /* also store char in lookahead buffer */
156 if (buf_defined(&la))
157 {
158 buf_write_u8(&la, c);
159 if (!isprint(c) && !isspace(c)) /* not ascii? */
160 {
161 if (verbose)
162 {
164 "recv_line: Non-ASCII character (%d) read on recv()", (int)c);
165 }
166 *lookahead = la;
167 return false;
168 }
169 }
170
171 /* end of line? */
172 if (lastc == '\r' && c == '\n')
173 {
174 break;
175 }
176
177 lastc = c;
178 }
179
180 /* append trailing null */
181 if (len > 0)
182 {
183 *buf++ = '\0';
184 }
185
186 return true;
187
188error:
189 return false;
190}
191
192static bool
193send_line(socket_descriptor_t sd, const char *buf)
194{
195 const ssize_t size = send(sd, buf, strlen(buf), MSG_NOSIGNAL);
196 if (size != (ssize_t)strlen(buf))
197 {
198 msg(D_LINK_ERRORS | M_ERRNO, "send_line: TCP port write failed on send()");
199 return false;
200 }
201 return true;
202}
203
204static bool
206{
207 bool ret;
208
209 struct buffer buf = alloc_buf(strlen(src) + 3);
210 ASSERT(buf_write(&buf, src, strlen(src)));
211 ASSERT(buf_write(&buf, "\r\n", 3));
212 ret = send_line(sd, BSTR(&buf));
213 free_buf(&buf);
214 return ret;
215}
216
217static bool
219{
220 return send_line_crlf(sd, "");
221}
222
223uint8_t *
225{
226 uint8_t *ret = NULL;
227 char *b64out = NULL;
228 ASSERT(openvpn_base64_encode((const void *)str, src_len, &b64out) >= 0);
229 ret = (uint8_t *)string_alloc(b64out, gc);
230 free(b64out);
231 return ret;
232}
233
234uint8_t *
236{
237 return make_base64_string2(str, (int)strlen((const char *)str), gc);
238}
239
240static const char *
242{
243 struct buffer out = alloc_buf_gc(strlen(p->up.username) + strlen(p->up.password) + 2, gc);
244 ASSERT(strlen(p->up.username) > 0);
245 buf_printf(&out, "%s:%s", p->up.username, p->up.password);
246 char *ret = (char *)make_base64_string((const uint8_t *)BSTR(&out), gc);
247 secure_memzero(BSTR(&out), out.len);
248 return ret;
249}
250
251static void
256
257static void
259{
260 /*
261 * in case of forced (re)load, make sure the static storage is set as
262 * undefined, otherwise get_user_pass() won't try to load any credential
263 */
264 if (force)
265 {
267 }
268
270 {
271 unsigned int flags = GET_USER_PASS_MANAGEMENT;
272 const char *auth_file = p->options.auth_file;
273 if (p->options.auth_file_up)
274 {
275 auth_file = p->options.auth_file_up;
276 }
277 if (p->queried_creds && !static_proxy_user_pass.nocache)
278 {
280 }
281 if (p->options.inline_creds)
282 {
284 }
286 static_proxy_user_pass.nocache = p->options.nocache;
288 }
289
290 /*
291 * Using cached credentials
292 */
293 p->queried_creds = true;
294 p->up = static_proxy_user_pass; /* this is a copy of protected memory */
295}
296
297#if 0
298/* function only used in #if 0 debug statement */
299static void
301 int timeout,
302 volatile int *signal_received)
303{
304 char buf[256];
305 while (true)
306 {
307 if (!recv_line(sd, buf, sizeof(buf), timeout, true, NULL, signal_received))
308 {
309 return;
310 }
311 chomp(buf);
312 msg(D_PROXY, "PROXY HEADER: '%s'", buf);
313 }
314}
315#endif
316
317/*
318 * Extract the Proxy-Authenticate header from the stream.
319 * Consumes all headers.
320 */
321static int
323 volatile int *signal_received)
324{
325 char buf[256];
326 int ret = HTTP_AUTH_NONE;
327 while (true)
328 {
329 if (!recv_line(sd, buf, sizeof(buf), timeout, true, NULL, signal_received))
330 {
331 free(*data);
332 *data = NULL;
333 return HTTP_AUTH_NONE;
334 }
335 chomp(buf);
336 if (!strlen(buf))
337 {
338 return ret;
339 }
340 if (ret == HTTP_AUTH_NONE && !strncmp(buf, "Proxy-Authenticate: ", 20))
341 {
342 if (!strncmp(buf + 20, "Basic ", 6))
343 {
344 msg(D_PROXY, "PROXY AUTH BASIC: '%s'", buf);
345 *data = string_alloc(buf + 26, NULL);
346 ret = HTTP_AUTH_BASIC;
347 }
348#if PROXY_DIGEST_AUTH
349 else if (!strncmp(buf + 20, "Digest ", 7))
350 {
351 msg(D_PROXY, "PROXY AUTH DIGEST: '%s'", buf);
352 *data = string_alloc(buf + 27, NULL);
353 ret = HTTP_AUTH_DIGEST;
354 }
355#endif
356#if NTLM
357 else if (!strncmp(buf + 20, "NTLM", 4))
358 {
359 msg(D_PROXY, "PROXY AUTH NTLM: '%s'", buf);
360 *data = NULL;
361 ret = HTTP_AUTH_NTLM2;
362 }
363#endif
364 }
365 }
366}
367
368static void
370{
371 free(p->proxy_authenticate);
372 p->proxy_authenticate = data;
373}
374
375/*
376 * Parse out key/value pairs from Proxy-Authenticate string.
377 * Return true on success, or false on parse failure.
378 */
379static bool
380get_key_value(const char *str, /* source string */
381 char *key, /* key stored here */
382 char *value, /* value stored here */
383 int max_key_len, int max_value_len, const char **endptr) /* next search position */
384{
385 int c;
386 bool starts_with_quote = false;
387 bool escape = false;
388
389 for (c = max_key_len - 1; (*str && (*str != '=') && c--);)
390 {
391 *key++ = *str++;
392 }
393 *key = '\0';
394
395 if ('=' != *str++)
396 {
397 /* no key/value found */
398 return false;
399 }
400
401 if ('\"' == *str)
402 {
403 /* quoted string */
404 str++;
405 starts_with_quote = true;
406 }
407
408 for (c = max_value_len - 1; *str && c--; str++)
409 {
410 switch (*str)
411 {
412 case '\\':
413 if (!escape)
414 {
415 /* possibly the start of an escaped quote */
416 escape = true;
417 *value++ = '\\'; /* even though this is an escape character, we still
418 * store it as-is in the target buffer */
419 continue;
420 }
421 break;
422
423 case ',':
425 {
426 /* this signals the end of the value if we didn't get a starting quote
427 * and then we do "sloppy" parsing */
428 c = 0; /* the end */
429 continue;
430 }
431 break;
432
433 case '\r':
434 case '\n':
435 /* end of string */
436 c = 0;
437 continue;
438
439 case '\"':
441 {
442 /* end of string */
443 c = 0;
444 continue;
445 }
446 break;
447 }
448 escape = false;
449 *value++ = *str;
450 }
451 *value = '\0';
452
453 *endptr = str;
454
455 return true; /* success */
456}
457
458static char *
459get_pa_var(const char *key, const char *pa, struct gc_arena *gc)
460{
461 char k[64];
462 char v[256];
463 const char *content = pa;
464
465 while (true)
466 {
467 const int status = get_key_value(content, k, v, sizeof(k), sizeof(v), &content);
468 if (status)
469 {
470 if (!strcmp(key, k))
471 {
472 return string_alloc(v, gc);
473 }
474 }
475 else
476 {
477 return NULL;
478 }
479
480 /* advance to start of next key */
481 if (*content == ',')
482 {
483 ++content;
484 }
485 while (*content && isspace(*content))
486 {
487 ++content;
488 }
489 }
490}
491
492struct http_proxy_info *
494{
495 struct http_proxy_info *p;
496
497 if (!o || !o->server)
498 {
499 msg(M_FATAL, "HTTP_PROXY: server not specified");
500 }
501
502 ASSERT(o->port);
503
505 p->options = *o;
506
507 /* parse authentication method */
509 if (o->auth_method_string)
510 {
511 if (!strcmp(o->auth_method_string, "none"))
512 {
514 }
515 else if (!strcmp(o->auth_method_string, "basic"))
516 {
518 }
519#if NTLM
520 else if (!strcmp(o->auth_method_string, "ntlm"))
521 {
522 msg(M_WARN,
523 "NTLM v1 authentication has been removed in OpenVPN 2.7. Will try to use NTLM v2 authentication.");
525 }
526 else if (!strcmp(o->auth_method_string, "ntlm2"))
527 {
529 }
530#endif
531 else
532 {
533 msg(M_FATAL, "ERROR: unknown HTTP authentication method: '%s'", o->auth_method_string);
534 }
535 }
536
537 /* When basic or NTLMv2 authentication is requested, get credentials now.
538 * In case of "auto" negotiation credentials will be retrieved later once
539 * we know whether we need any. */
541 {
543 }
544
545#if !NTLM
547 {
548 msg(M_FATAL,
549 "Sorry, this version of " PACKAGE_NAME " was built without NTLM Proxy support.");
550 }
551#endif
552
553 p->defined = true;
554 return p;
555}
556
557void
559{
560 free(hp);
561}
562
563static bool
564add_proxy_headers(struct http_proxy_info *p, socket_descriptor_t sd, /* already open to proxy */
565 const char *host /* openvpn server remote */
566)
567{
568 char buf[512];
569 int i;
570 bool host_header_sent = false;
571
572 /*
573 * Send custom headers if provided
574 * If content is NULL the whole header is in name
575 * Also remember if we already sent a Host: header
576 */
577 for (i = 0; i < MAX_CUSTOM_HTTP_HEADER && p->options.custom_headers[i].name; i++)
578 {
580 {
581 snprintf(buf, sizeof(buf), "%s: %s", p->options.custom_headers[i].name,
583 if (!strcasecmp(p->options.custom_headers[i].name, "Host"))
584 {
585 host_header_sent = true;
586 }
587 }
588 else
589 {
590 snprintf(buf, sizeof(buf), "%s", p->options.custom_headers[i].name);
591 if (!strncasecmp(p->options.custom_headers[i].name, "Host:", 5))
592 {
593 host_header_sent = true;
594 }
595 }
596
597 msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
598 if (!send_line_crlf(sd, buf))
599 {
600 return false;
601 }
602 }
603
604 if (!host_header_sent)
605 {
606 snprintf(buf, sizeof(buf), "Host: %s", host);
607 msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
608 if (!send_line_crlf(sd, buf))
609 {
610 return false;
611 }
612 }
613
614 /* send User-Agent string if provided */
615 if (p->options.user_agent)
616 {
617 snprintf(buf, sizeof(buf), "User-Agent: %s", p->options.user_agent);
618 msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
619 if (!send_line_crlf(sd, buf))
620 {
621 return false;
622 }
623 }
624
625 return true;
626}
627
628
629bool
631 socket_descriptor_t sd, /* already open to proxy */
632 const char *host, /* openvpn server remote */
633 const char *port, /* openvpn server port */
634 struct event_timeout *server_poll_timeout, struct buffer *lookahead,
635 struct signal_info *sig_info)
636{
637 struct gc_arena gc = gc_new();
638 char buf[512];
639 int status;
640 int nparms;
641 bool ret = false;
642 bool processed = false;
643 volatile int *signal_received = &sig_info->signal_received;
644
645 /* get user/pass if not previously given */
648 {
649 get_user_pass_http(p, false);
650
651 if (p->up.nocache)
652 {
654 }
656 }
657
658 /* are we being called again after getting the digest server nonce in the previous transaction?
659 */
661 {
662 nparms = 1;
663 status = 407;
664 }
665 else
666 {
667 /* format HTTP CONNECT message */
668 snprintf(buf, sizeof(buf), "CONNECT %s:%s HTTP/%s", host, port, p->options.http_version);
669
670 msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
671
672 /* send HTTP CONNECT message to proxy */
673 if (!send_line_crlf(sd, buf))
674 {
675 goto error;
676 }
677
678 if (!add_proxy_headers(p, sd, host))
679 {
680 goto error;
681 }
682
683 /* auth specified? */
684 switch (p->auth_method)
685 {
686 case HTTP_AUTH_NONE:
687 break;
688
689 case HTTP_AUTH_BASIC:
690 snprintf(buf, sizeof(buf), "Proxy-Authorization: Basic %s",
692 msg(D_PROXY, "Attempting Basic Proxy-Authorization");
693 dmsg(D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf);
694 if (!send_line_crlf(sd, buf))
695 {
696 goto error;
697 }
698 break;
699
700#if NTLM
701 case HTTP_AUTH_NTLM2:
702 /* keep-alive connection */
703 snprintf(buf, sizeof(buf), "Proxy-Connection: Keep-Alive");
704 if (!send_line_crlf(sd, buf))
705 {
706 goto error;
707 }
708
709 snprintf(buf, sizeof(buf), "Proxy-Authorization: NTLM %s", ntlm_phase_1(p, &gc));
710 msg(D_PROXY, "Attempting NTLM Proxy-Authorization phase 1");
711 dmsg(D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf);
712 if (!send_line_crlf(sd, buf))
713 {
714 goto error;
715 }
716 break;
717#endif
718
719 default:
720 ASSERT(0);
721 }
722
723 /* clear any sensitive content in buf */
724 secure_memzero(buf, sizeof(buf));
725
726 /* send empty CR, LF */
727 if (!send_crlf(sd))
728 {
729 goto error;
730 }
731
732 /* receive reply from proxy */
733 if (!recv_line(sd, buf, sizeof(buf), get_server_poll_remaining_time(server_poll_timeout),
734 true, NULL, signal_received))
735 {
736 goto error;
737 }
738
739 /* remove trailing CR, LF */
740 chomp(buf);
741
742 msg(D_PROXY, "HTTP proxy returned: '%s'", buf);
743
744 /* parse return string */
745 nparms = sscanf(buf, "%*s %d", &status);
746 }
747
748 /* check for a "407 Proxy Authentication Required" response */
749 while (nparms >= 1 && status == 407)
750 {
751 msg(D_PROXY, "Proxy requires authentication");
752
753 if (p->auth_method == HTTP_AUTH_BASIC && !processed)
754 {
755 processed = true;
756 }
757 else if (p->auth_method == HTTP_AUTH_NTLM2 && !processed) /* check for NTLM */
758 {
759#if NTLM
760 /* look for the phase 2 response */
761 char buf2[512];
762 while (true)
763 {
764 if (!recv_line(sd, buf, sizeof(buf),
765 get_server_poll_remaining_time(server_poll_timeout), true, NULL,
766 signal_received))
767 {
768 goto error;
769 }
770 chomp(buf);
771 msg(D_PROXY, "HTTP proxy returned: '%s'", buf);
772
773 char get[80];
774 CLEAR(buf2);
775 snprintf(get, sizeof(get), "%%*s NTLM %%%zus", sizeof(buf2) - 1);
776 nparms = sscanf(buf, get, buf2);
777
778 /* check for "Proxy-Authenticate: NTLM TlRM..." */
779 if (nparms == 1)
780 {
781 /* parse buf2 */
782 msg(D_PROXY, "auth string: '%s'", buf2);
783 break;
784 }
785 }
786 /* if we are here then auth string was got */
787 msg(D_PROXY, "Received NTLM Proxy-Authorization phase 2 response");
788
789 /* receive and discard everything else */
790 while (recv_line(sd, NULL, 0, 2, true, NULL, signal_received))
791 {
792 }
793
794 /* now send the phase 3 reply */
795
796 /* format HTTP CONNECT message */
797 snprintf(buf, sizeof(buf), "CONNECT %s:%s HTTP/%s", host, port,
799
800 msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
801
802 /* send HTTP CONNECT message to proxy */
803 if (!send_line_crlf(sd, buf))
804 {
805 goto error;
806 }
807
808 /* keep-alive connection */
809 snprintf(buf, sizeof(buf), "Proxy-Connection: Keep-Alive");
810 if (!send_line_crlf(sd, buf))
811 {
812 goto error;
813 }
814
815 /* send HOST etc, */
816 if (!add_proxy_headers(p, sd, host))
817 {
818 goto error;
819 }
820
821 msg(D_PROXY, "Attempting NTLM Proxy-Authorization phase 3");
822 {
823 const char *np3 = ntlm_phase_3(p, buf2, &gc);
824 if (!np3)
825 {
826 msg(D_PROXY,
827 "NTLM Proxy-Authorization phase 3 failed: received corrupted data from proxy server");
828 goto error;
829 }
830 snprintf(buf, sizeof(buf), "Proxy-Authorization: NTLM %s", np3);
831 }
832
833 msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
834 if (!send_line_crlf(sd, buf))
835 {
836 goto error;
837 }
838 /* ok so far... */
839 /* send empty CR, LF */
840 if (!send_crlf(sd))
841 {
842 goto error;
843 }
844
845 /* receive reply from proxy */
846 if (!recv_line(sd, buf, sizeof(buf),
847 get_server_poll_remaining_time(server_poll_timeout), true, NULL,
848 signal_received))
849 {
850 goto error;
851 }
852
853 /* remove trailing CR, LF */
854 chomp(buf);
855
856 msg(D_PROXY, "HTTP proxy returned: '%s'", buf);
857
858 /* parse return string */
859 nparms = sscanf(buf, "%*s %d", &status);
860 processed = true;
861#endif /* if NTLM */
862 }
863#if PROXY_DIGEST_AUTH
864 else if (p->auth_method == HTTP_AUTH_DIGEST && !processed)
865 {
866 char *pa = p->proxy_authenticate;
867 const int method = p->auth_method;
868 ASSERT(pa);
869
870 if (method == HTTP_AUTH_DIGEST)
871 {
872 const char *http_method = "CONNECT";
873 const char *nonce_count = "00000001";
874 const char *qop = "auth";
875 const char *username = p->up.username;
876 const char *password = p->up.password;
877 char *opaque_kv = "";
878 char uri[128];
879 uint8_t cnonce_raw[8];
880 uint8_t *cnonce;
881 HASHHEX session_key;
882 HASHHEX response;
883
884 const char *realm = get_pa_var("realm", pa, &gc);
885 const char *nonce = get_pa_var("nonce", pa, &gc);
886 const char *algor = get_pa_var("algorithm", pa, &gc);
887 const char *opaque = get_pa_var("opaque", pa, &gc);
888
889 if (!realm || !nonce)
890 {
891 msg(D_LINK_ERRORS, "HTTP proxy: digest auth failed, malformed response "
892 "from server: realm= or nonce= missing");
893 goto error;
894 }
895
896 /* generate a client nonce */
897 ASSERT(rand_bytes(cnonce_raw, sizeof(cnonce_raw)));
898 cnonce = make_base64_string2(cnonce_raw, sizeof(cnonce_raw), &gc);
899
900
901 /* build the digest response */
902 snprintf(uri, sizeof(uri), "%s:%s", host, port);
903
904 if (opaque)
905 {
906 const int len = strlen(opaque) + 16;
907 opaque_kv = gc_malloc(len, false, &gc);
908 snprintf(opaque_kv, len, ", opaque=\"%s\"", opaque);
909 }
910
911 DigestCalcHA1(algor, username, realm, password, nonce, (char *)cnonce, session_key);
912 DigestCalcResponse(session_key, nonce, nonce_count, (char *)cnonce, qop,
913 http_method, uri, NULL, response);
914
915 /* format HTTP CONNECT message */
916 snprintf(buf, sizeof(buf), "%s %s HTTP/%s", http_method, uri,
918
919 msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
920
921 /* send HTTP CONNECT message to proxy */
922 if (!send_line_crlf(sd, buf))
923 {
924 goto error;
925 }
926
927 /* send HOST etc, */
928 if (!add_proxy_headers(p, sd, host))
929 {
930 goto error;
931 }
932
933 /* send digest response */
934 int sret = snprintf(
935 buf, sizeof(buf),
936 "Proxy-Authorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", qop=%s, nc=%s, cnonce=\"%s\", response=\"%s\"%s",
937 username, realm, nonce, uri, qop, nonce_count, cnonce, response, opaque_kv);
938 if (sret >= sizeof(buf))
939 {
940 goto error;
941 }
942
943 msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
944 if (!send_line_crlf(sd, buf))
945 {
946 goto error;
947 }
948 if (!send_crlf(sd))
949 {
950 goto error;
951 }
952 /* clear any sensitive content in buf */
953 secure_memzero(buf, sizeof(buf));
954
955 /* receive reply from proxy */
956 if (!recv_line(sd, buf, sizeof(buf),
957 get_server_poll_remaining_time(server_poll_timeout), true, NULL,
958 signal_received))
959 {
960 goto error;
961 }
962
963 /* remove trailing CR, LF */
964 chomp(buf);
965
966 msg(D_PROXY, "HTTP proxy returned: '%s'", buf);
967
968 /* parse return string */
969 nparms = sscanf(buf, "%*s %d", &status);
970 processed = true;
971 }
972 else
973 {
974 msg(D_PROXY, "HTTP proxy: digest method not supported");
975 goto error;
976 }
977 }
978#endif /* if PROXY_DIGEST_AUTH */
979 else if (p->options.auth_retry)
980 {
981 /* figure out what kind of authentication the proxy needs */
982 char *pa = NULL;
983 const int method = get_proxy_authenticate(
984 sd, get_server_poll_remaining_time(server_poll_timeout), &pa, signal_received);
985 if (method != HTTP_AUTH_NONE)
986 {
987 if (pa)
988 {
989 msg(D_PROXY, "HTTP proxy authenticate '%s'", pa);
990 }
991 if (p->options.auth_retry == PAR_NCT && method == HTTP_AUTH_BASIC)
992 {
993 msg(D_PROXY,
994 "HTTP proxy: support for basic auth and other cleartext proxy auth methods is disabled");
995 free(pa);
996 goto error;
997 }
998 p->auth_method = method;
1000 ret = true;
1001 goto done;
1002 }
1003 else
1004 {
1005 msg(D_PROXY,
1006 "HTTP proxy: do not recognize the authentication method required by proxy");
1007 free(pa);
1008 goto error;
1009 }
1010 }
1011 else
1012 {
1013 if (!processed)
1014 {
1015 msg(D_PROXY, "HTTP proxy: no support for proxy authentication method");
1016 }
1017 goto error;
1018 }
1019 }
1020
1021 /* check return code, success = 200 */
1022 if (nparms < 1 || status != 200)
1023 {
1024 msg(D_LINK_ERRORS, "HTTP proxy returned bad status");
1025#if 0
1026 /* DEBUGGING -- show a multi-line HTTP error response */
1027 dump_residual(sd, get_server_poll_remaining_time(server_poll_timeout), signal_received);
1028#endif
1029 goto error;
1030 }
1031
1032 /* SUCCESS */
1033
1034 /* receive line from proxy and discard */
1035 if (!recv_line(sd, NULL, 0, get_server_poll_remaining_time(server_poll_timeout), true, NULL,
1036 signal_received))
1037 {
1038 goto error;
1039 }
1040
1041 /*
1042 * Toss out any extraneous chars, but don't throw away the
1043 * start of the OpenVPN data stream (put it in lookahead).
1044 */
1045 while (recv_line(sd, NULL, 0, 2, false, lookahead, signal_received))
1046 {
1047 }
1048
1049 /* reset queried_creds so that we don't think that the next creds request is due to an auth
1050 * error */
1051 p->queried_creds = false;
1052
1053#if 0
1054 if (lookahead && BLEN(lookahead))
1055 {
1056 msg(M_INFO, "HTTP PROXY: lookahead: %s", format_hex(BPTR(lookahead), BLEN(lookahead), 0));
1057 }
1058#endif
1059
1060done:
1061 purge_user_pass(&p->up, true);
1062 gc_free(&gc);
1063 return ret;
1064
1065error:
1066 purge_user_pass(&p->up, true);
1067 register_signal(sig_info, SIGUSR1, "HTTP proxy error"); /* SOFT-SIGUSR1 -- HTTP proxy error */
1068 gc_free(&gc);
1069 return ret;
1070}
1071
1072#if defined(__GNUC__) || defined(__clang__)
1073#pragma GCC diagnostic pop
1074#endif
void free_buf(struct buffer *buf)
Definition buffer.c:184
bool buf_printf(struct buffer *buf, const char *format,...)
Definition buffer.c:241
void chomp(char *str)
Definition buffer.c:614
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Definition buffer.c:336
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition buffer.c:89
struct buffer alloc_buf(size_t size)
Definition buffer.c:63
char * string_alloc(const char *str, struct gc_arena *gc)
Definition buffer.c:649
static char * format_hex(const uint8_t *data, int size, int maxoutput, struct gc_arena *gc)
Definition buffer.h:503
#define BSTR(buf)
Definition buffer.h:128
#define BPTR(buf)
Definition buffer.h:123
static void secure_memzero(void *data, size_t len)
Securely zeroise memory.
Definition buffer.h:414
static bool buf_write(struct buffer *dest, const void *src, size_t size)
Definition buffer.h:660
static bool buf_write_u8(struct buffer *dest, uint8_t data)
Definition buffer.h:684
#define ALLOC_OBJ_CLEAR_GC(dptr, type, gc)
Definition buffer.h:1079
#define BLEN(buf)
Definition buffer.h:126
static void gc_free(struct gc_arena *a)
Definition buffer.h:1015
#define ALLOC_OBJ_CLEAR(dptr, type)
Definition buffer.h:1042
static bool buf_defined(const struct buffer *buf)
Definition buffer.h:228
#define buf_init(buf, offset)
Definition buffer.h:209
static struct gc_arena gc_new(void)
Definition buffer.h:1007
#define PACKAGE_NAME
Definition config.h:492
Data Channel Cryptography Module.
int rand_bytes(uint8_t *output, int len)
Wrapper for secure random number generator.
#define D_PROXY
Definition errlevel.h:73
#define D_SHOW_KEYS
Definition errlevel.h:120
#define M_INFO
Definition errlevel.h:54
#define D_LINK_ERRORS
Definition errlevel.h:56
static void openvpn_fd_set(socket_descriptor_t fd, fd_set *setp)
Definition fdmisc.h:39
int get_server_poll_remaining_time(struct event_timeout *server_poll_timeout)
Definition forward.c:503
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)
Definition httpdigest.c:71
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)
Definition httpdigest.c:101
static SERVICE_STATUS status
Definition interactive.c:51
void unprotect_user_pass(struct user_pass *up)
Decrypt username and password buffers in user_pass.
Definition misc.c:812
void purge_user_pass(struct user_pass *up, const bool force)
Definition misc.c:474
void protect_user_pass(struct user_pass *up)
Encrypt username and password buffers in user_pass.
Definition misc.c:792
#define GET_USER_PASS_MANAGEMENT
Definition misc.h:110
#define GET_USER_PASS_INLINE_CREDS
indicates that auth_file is actually inline creds
Definition misc.h:123
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.
Definition misc.h:150
#define GET_USER_PASS_PREVIOUS_CREDS_FAILED
Definition misc.h:116
const char * ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_arena *gc)
Definition ntlm.c:194
const char * ntlm_phase_1(const struct http_proxy_info *p, struct gc_arena *gc)
Definition ntlm.c:177
#define CLEAR(x)
Definition basic.h:32
#define M_FATAL
Definition error.h:90
#define dmsg(flags,...)
Definition error.h:172
#define msg(flags,...)
Definition error.h:152
#define ASSERT(x)
Definition error.h:219
#define M_WARN
Definition error.h:92
#define M_ERRNO
Definition error.h:95
static bool send_crlf(socket_descriptor_t sd)
Definition proxy.c:218
static struct user_pass static_proxy_user_pass
Definition proxy.c:63
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)
Definition proxy.c:66
void http_proxy_close(struct http_proxy_info *hp)
Definition proxy.c:558
static void clear_user_pass_http(void)
Definition proxy.c:252
static char * get_pa_var(const char *key, const char *pa, struct gc_arena *gc)
Definition proxy.c:459
static const char * username_password_as_base64(const struct http_proxy_info *p, struct gc_arena *gc)
Definition proxy.c:241
struct http_proxy_info * http_proxy_new(const struct http_proxy_options *o)
Definition proxy.c:493
struct http_proxy_options * init_http_proxy_options_once(struct http_proxy_options **hpo, struct gc_arena *gc)
Definition proxy.c:45
static void store_proxy_authenticate(struct http_proxy_info *p, char *data)
Definition proxy.c:369
static bool get_key_value(const char *str, char *key, char *value, int max_key_len, int max_value_len, const char **endptr)
Definition proxy.c:380
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)
Definition proxy.c:630
static bool send_line(socket_descriptor_t sd, const char *buf)
Definition proxy.c:193
static bool send_line_crlf(socket_descriptor_t sd, const char *src)
Definition proxy.c:205
static void get_user_pass_http(struct http_proxy_info *p, const bool force)
Definition proxy.c:258
uint8_t * make_base64_string2(const uint8_t *str, int src_len, struct gc_arena *gc)
Definition proxy.c:224
uint8_t * make_base64_string(const uint8_t *str, struct gc_arena *gc)
Definition proxy.c:235
static bool add_proxy_headers(struct http_proxy_info *p, socket_descriptor_t sd, const char *host)
Definition proxy.c:564
static int get_proxy_authenticate(socket_descriptor_t sd, int timeout, char **data, volatile int *signal_received)
Definition proxy.c:322
#define UP_TYPE_PROXY
Definition proxy.c:42
#define PAR_NCT
Definition proxy.h:51
#define MAX_CUSTOM_HTTP_HEADER
Definition proxy.h:43
#define HTTP_AUTH_BASIC
Definition proxy.h:31
#define HTTP_AUTH_NONE
Definition proxy.h:30
#define HTTP_AUTH_NTLM2
Definition proxy.h:34
#define HTTP_AUTH_DIGEST
Definition proxy.h:32
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.
Definition sig.c:228
static void get_signal(volatile int *sig)
Copy the global signal_received (if non-zero) to the passed-in argument sig.
Definition sig.h:109
#define MSG_NOSIGNAL
Definition socket.h:242
int openvpn_base64_encode(const void *data, int size, char **str)
Definition base64.c:51
Wrapper structure for dynamically allocated memory.
Definition buffer.h:60
uint8_t * data
Pointer to the allocated memory.
Definition buffer.h:67
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:65
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:116
const char * name
Definition proxy.h:39
const char * content
Definition proxy.h:40
struct user_pass up
Definition proxy.h:71
bool defined
Definition proxy.h:68
int auth_method
Definition proxy.h:69
bool queried_creds
Definition proxy.h:73
char * proxy_authenticate
Definition proxy.h:72
struct http_proxy_options options
Definition proxy.h:70
const char * http_version
Definition proxy.h:57
const char * port
Definition proxy.h:47
const char * user_agent
Definition proxy.h:58
const char * auth_method_string
Definition proxy.h:54
struct http_custom_header custom_headers[MAX_CUSTOM_HTTP_HEADER]
Definition proxy.h:59
const char * server
Definition proxy.h:46
Container for unidirectional cipher and HMAC key material.
Definition crypto.h:152
volatile int signal_received
Definition sig.h:42
bool defined
Definition misc.h:53
char password[USER_PASS_LEN]
Definition misc.h:68
bool nocache
Definition misc.h:57
char username[USER_PASS_LEN]
Definition misc.h:67
SOCKET socket_descriptor_t
Definition syshead.h:440
struct gc_arena gc
Definition test_ssl.c:131