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