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