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-2023 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 
45 struct http_proxy_options *
47  struct gc_arena *gc)
48 {
49  if (!*hpo)
50  {
51  ALLOC_OBJ_CLEAR_GC(*hpo, struct http_proxy_options, gc);
52  /* http proxy defaults */
53  (*hpo)->http_version = "1.0";
54  }
55  return *hpo;
56 }
57 
58 
59 /* cached proxy username/password */
61 
62 static 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 
189 error:
190  return false;
191 }
192 
193 static 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 
206 static 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 
220 static bool
222 {
223  return send_line_crlf(sd, "");
224 }
225 
226 uint8_t *
227 make_base64_string2(const uint8_t *str, int src_len, struct gc_arena *gc)
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 
237 uint8_t *
238 make_base64_string(const uint8_t *str, struct gc_arena *gc)
239 {
240  return make_base64_string2(str, strlen((const char *)str), gc);
241 }
242 
243 static 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  return (const char *)make_base64_string((const uint8_t *)BSTR(&out), gc);
251 }
252 
253 static void
255 {
257 }
258 
259 static void
260 get_user_pass_http(struct http_proxy_info *p, const bool force)
261 {
262  /*
263  * in case of forced (re)load, make sure the static storage is set as
264  * undefined, otherwise get_user_pass() won't try to load any credential
265  */
266  if (force)
267  {
269  }
270 
272  {
273  unsigned int flags = GET_USER_PASS_MANAGEMENT;
274  const char *auth_file = p->options.auth_file;
275  if (p->options.auth_file_up)
276  {
277  auth_file = p->options.auth_file_up;
278  }
279  if (p->queried_creds)
280  {
282  }
283  if (p->options.inline_creds)
284  {
286  }
288  auth_file,
290  flags);
291  p->queried_creds = true;
293  }
294 }
295 
296 #if 0
297 /* function only used in #if 0 debug statement */
298 static void
299 dump_residual(socket_descriptor_t sd,
300  int timeout,
301  volatile int *signal_received)
302 {
303  char buf[256];
304  while (true)
305  {
306  if (!recv_line(sd, buf, sizeof(buf), timeout, true, NULL, signal_received))
307  {
308  return;
309  }
310  chomp(buf);
311  msg(D_PROXY, "PROXY HEADER: '%s'", buf);
312  }
313 }
314 #endif
315 
316 /*
317  * Extract the Proxy-Authenticate header from the stream.
318  * Consumes all headers.
319  */
320 static int
322  int timeout,
323  char **data,
324  volatile int *signal_received)
325 {
326  char buf[256];
327  int ret = HTTP_AUTH_NONE;
328  while (true)
329  {
330  if (!recv_line(sd, buf, sizeof(buf), timeout, true, NULL, signal_received))
331  {
332  free(*data);
333  *data = NULL;
334  return HTTP_AUTH_NONE;
335  }
336  chomp(buf);
337  if (!strlen(buf))
338  {
339  return ret;
340  }
341  if (ret == HTTP_AUTH_NONE && !strncmp(buf, "Proxy-Authenticate: ", 20))
342  {
343  if (!strncmp(buf+20, "Basic ", 6))
344  {
345  msg(D_PROXY, "PROXY AUTH BASIC: '%s'", buf);
346  *data = string_alloc(buf+26, NULL);
347  ret = HTTP_AUTH_BASIC;
348  }
349 #if PROXY_DIGEST_AUTH
350  else if (!strncmp(buf+20, "Digest ", 7))
351  {
352  msg(D_PROXY, "PROXY AUTH DIGEST: '%s'", buf);
353  *data = string_alloc(buf+27, NULL);
354  ret = HTTP_AUTH_DIGEST;
355  }
356 #endif
357 #if NTLM
358  else if (!strncmp(buf+20, "NTLM", 4))
359  {
360  msg(D_PROXY, "PROXY AUTH NTLM: '%s'", buf);
361  *data = NULL;
362  ret = HTTP_AUTH_NTLM2;
363  }
364 #endif
365  }
366  }
367 }
368 
369 static void
371 {
372  free(p->proxy_authenticate);
374 }
375 
376 /*
377  * Parse out key/value pairs from Proxy-Authenticate string.
378  * Return true on success, or false on parse failure.
379  */
380 static bool
381 get_key_value(const char *str, /* source string */
382  char *key, /* key stored here */
383  char *value, /* value stored here */
384  int max_key_len,
385  int max_value_len,
386  const char **endptr) /* next search position */
387 {
388  int c;
389  bool starts_with_quote = false;
390  bool escape = false;
391 
392  for (c = max_key_len-1; (*str && (*str != '=') && c--); )
393  {
394  *key++ = *str++;
395  }
396  *key = '\0';
397 
398  if ('=' != *str++)
399  {
400  /* no key/value found */
401  return false;
402  }
403 
404  if ('\"' == *str)
405  {
406  /* quoted string */
407  str++;
408  starts_with_quote = true;
409  }
410 
411  for (c = max_value_len-1; *str && c--; str++)
412  {
413  switch (*str)
414  {
415  case '\\':
416  if (!escape)
417  {
418  /* possibly the start of an escaped quote */
419  escape = true;
420  *value++ = '\\'; /* even though this is an escape character, we still
421  * store it as-is in the target buffer */
422  continue;
423  }
424  break;
425 
426  case ',':
427  if (!starts_with_quote)
428  {
429  /* this signals the end of the value if we didn't get a starting quote
430  * and then we do "sloppy" parsing */
431  c = 0; /* the end */
432  continue;
433  }
434  break;
435 
436  case '\r':
437  case '\n':
438  /* end of string */
439  c = 0;
440  continue;
441 
442  case '\"':
443  if (!escape && starts_with_quote)
444  {
445  /* end of string */
446  c = 0;
447  continue;
448  }
449  break;
450  }
451  escape = false;
452  *value++ = *str;
453  }
454  *value = '\0';
455 
456  *endptr = str;
457 
458  return true; /* success */
459 }
460 
461 static char *
462 get_pa_var(const char *key, const char *pa, struct gc_arena *gc)
463 {
464  char k[64];
465  char v[256];
466  const char *content = pa;
467 
468  while (true)
469  {
470  const int status = get_key_value(content, k, v, sizeof(k), sizeof(v), &content);
471  if (status)
472  {
473  if (!strcmp(key, k))
474  {
475  return string_alloc(v, gc);
476  }
477  }
478  else
479  {
480  return NULL;
481  }
482 
483  /* advance to start of next key */
484  if (*content == ',')
485  {
486  ++content;
487  }
488  while (*content && isspace(*content))
489  {
490  ++content;
491  }
492  }
493 }
494 
495 struct http_proxy_info *
497 {
498  struct http_proxy_info *p;
499 
500  if (!o || !o->server)
501  {
502  msg(M_FATAL, "HTTP_PROXY: server not specified");
503  }
504 
505  ASSERT(o->port);
506 
507  ALLOC_OBJ_CLEAR(p, struct http_proxy_info);
508  p->options = *o;
509 
510  /* parse authentication method */
512  if (o->auth_method_string)
513  {
514  if (!strcmp(o->auth_method_string, "none"))
515  {
517  }
518  else if (!strcmp(o->auth_method_string, "basic"))
519  {
521  }
522 #if NTLM
523  else if (!strcmp(o->auth_method_string, "ntlm"))
524  {
525  msg(M_WARN, "NTLM v1 authentication has been removed in OpenVPN 2.7. Will try to use NTLM v2 authentication.");
527  }
528  else if (!strcmp(o->auth_method_string, "ntlm2"))
529  {
531  }
532 #endif
533  else
534  {
535  msg(M_FATAL, "ERROR: unknown HTTP authentication method: '%s'",
536  o->auth_method_string);
537  }
538  }
539 
540  /* When basic or NTLMv2 authentication is requested, get credentials now.
541  * In case of "auto" negotiation credentials will be retrieved later once
542  * we know whether we need any. */
544  {
545  get_user_pass_http(p, true);
546  }
547 
548 #if !NTLM
549  if (p->auth_method == HTTP_AUTH_NTLM2)
550  {
551  msg(M_FATAL, "Sorry, this version of " PACKAGE_NAME " was built without NTLM Proxy support.");
552  }
553 #endif
554 
555  p->defined = true;
556  return p;
557 }
558 
559 void
561 {
562  free(hp);
563 }
564 
565 static bool
567  socket_descriptor_t sd, /* already open to proxy */
568  const char *host, /* openvpn server remote */
569  const char *port /* openvpn server port */
570  )
571 {
572  char buf[512];
573  int i;
574  bool host_header_sent = false;
575 
576  /*
577  * Send custom headers if provided
578  * If content is NULL the whole header is in name
579  * Also remember if we already sent a Host: header
580  */
581  for (i = 0; i < MAX_CUSTOM_HTTP_HEADER && p->options.custom_headers[i].name; i++)
582  {
583  if (p->options.custom_headers[i].content)
584  {
585  openvpn_snprintf(buf, sizeof(buf), "%s: %s",
588  if (!strcasecmp(p->options.custom_headers[i].name, "Host"))
589  {
590  host_header_sent = true;
591  }
592  }
593  else
594  {
595  openvpn_snprintf(buf, sizeof(buf), "%s",
596  p->options.custom_headers[i].name);
597  if (!strncasecmp(p->options.custom_headers[i].name, "Host:", 5))
598  {
599  host_header_sent = true;
600  }
601  }
602 
603  msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
604  if (!send_line_crlf(sd, buf))
605  {
606  return false;
607  }
608  }
609 
610  if (!host_header_sent)
611  {
612  openvpn_snprintf(buf, sizeof(buf), "Host: %s", host);
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  /* send User-Agent string if provided */
621  if (p->options.user_agent)
622  {
623  openvpn_snprintf(buf, sizeof(buf), "User-Agent: %s",
624  p->options.user_agent);
625  msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
626  if (!send_line_crlf(sd, buf))
627  {
628  return false;
629  }
630  }
631 
632  return true;
633 }
634 
635 
636 bool
638  socket_descriptor_t sd, /* already open to proxy */
639  const char *host, /* openvpn server remote */
640  const char *port, /* openvpn server port */
641  struct event_timeout *server_poll_timeout,
642  struct buffer *lookahead,
643  struct signal_info *sig_info)
644 {
645  struct gc_arena gc = gc_new();
646  char buf[512];
647  int status;
648  int nparms;
649  bool ret = false;
650  bool processed = false;
651  volatile int *signal_received = &sig_info->signal_received;
652 
653  /* get user/pass if not previously given */
654  if (p->auth_method == HTTP_AUTH_BASIC
656  || p->auth_method == HTTP_AUTH_NTLM2)
657  {
658  get_user_pass_http(p, false);
659  }
660 
661  /* are we being called again after getting the digest server nonce in the previous transaction? */
663  {
664  nparms = 1;
665  status = 407;
666  }
667  else
668  {
669  /* format HTTP CONNECT message */
670  openvpn_snprintf(buf, sizeof(buf), "CONNECT %s:%s HTTP/%s",
671  host,
672  port,
673  p->options.http_version);
674 
675  msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
676 
677  /* send HTTP CONNECT message to proxy */
678  if (!send_line_crlf(sd, buf))
679  {
680  goto error;
681  }
682 
683  if (!add_proxy_headers(p, sd, host, port))
684  {
685  goto error;
686  }
687 
688  /* auth specified? */
689  switch (p->auth_method)
690  {
691  case HTTP_AUTH_NONE:
692  break;
693 
694  case HTTP_AUTH_BASIC:
695  openvpn_snprintf(buf, sizeof(buf), "Proxy-Authorization: Basic %s",
697  msg(D_PROXY, "Attempting Basic Proxy-Authorization");
698  dmsg(D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf);
699  if (!send_line_crlf(sd, buf))
700  {
701  goto error;
702  }
703  break;
704 
705 #if NTLM
706  case HTTP_AUTH_NTLM2:
707  /* keep-alive connection */
708  openvpn_snprintf(buf, sizeof(buf), "Proxy-Connection: Keep-Alive");
709  if (!send_line_crlf(sd, buf))
710  {
711  goto error;
712  }
713 
714  openvpn_snprintf(buf, sizeof(buf), "Proxy-Authorization: NTLM %s",
715  ntlm_phase_1(p, &gc));
716  msg(D_PROXY, "Attempting NTLM Proxy-Authorization phase 1");
717  dmsg(D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf);
718  if (!send_line_crlf(sd, buf))
719  {
720  goto error;
721  }
722  break;
723 #endif
724 
725  default:
726  ASSERT(0);
727  }
728 
729  /* send empty CR, LF */
730  if (!send_crlf(sd))
731  {
732  goto error;
733  }
734 
735  /* receive reply from proxy */
736  if (!recv_line(sd, buf, sizeof(buf), get_server_poll_remaining_time(server_poll_timeout), true, NULL, signal_received))
737  {
738  goto error;
739  }
740 
741  /* remove trailing CR, LF */
742  chomp(buf);
743 
744  msg(D_PROXY, "HTTP proxy returned: '%s'", buf);
745 
746  /* parse return string */
747  nparms = sscanf(buf, "%*s %d", &status);
748 
749  }
750 
751  /* check for a "407 Proxy Authentication Required" response */
752  while (nparms >= 1 && status == 407)
753  {
754  msg(D_PROXY, "Proxy requires authentication");
755 
756  if (p->auth_method == HTTP_AUTH_BASIC && !processed)
757  {
758  processed = true;
759  }
760  else if (p->auth_method == HTTP_AUTH_NTLM2 && !processed) /* check for NTLM */
761  {
762 #if NTLM
763  /* look for the phase 2 response */
764  char buf2[512];
765  while (true)
766  {
767  if (!recv_line(sd, buf, sizeof(buf), get_server_poll_remaining_time(server_poll_timeout), true, NULL, signal_received))
768  {
769  goto error;
770  }
771  chomp(buf);
772  msg(D_PROXY, "HTTP proxy returned: '%s'", buf);
773 
774  char get[80];
775  CLEAR(buf2);
776  openvpn_snprintf(get, sizeof(get), "%%*s NTLM %%%zus", sizeof(buf2) - 1);
777  nparms = sscanf(buf, get, buf2);
778 
779  /* check for "Proxy-Authenticate: NTLM TlRM..." */
780  if (nparms == 1)
781  {
782  /* parse buf2 */
783  msg(D_PROXY, "auth string: '%s'", buf2);
784  break;
785  }
786  }
787  /* if we are here then auth string was got */
788  msg(D_PROXY, "Received NTLM Proxy-Authorization phase 2 response");
789 
790  /* receive and discard everything else */
791  while (recv_line(sd, NULL, 0, 2, true, NULL, signal_received))
792  {
793  }
794 
795  /* now send the phase 3 reply */
796 
797  /* format HTTP CONNECT message */
798  openvpn_snprintf(buf, sizeof(buf), "CONNECT %s:%s HTTP/%s",
799  host,
800  port,
801  p->options.http_version);
802 
803  msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
804 
805  /* send HTTP CONNECT message to proxy */
806  if (!send_line_crlf(sd, buf))
807  {
808  goto error;
809  }
810 
811  /* keep-alive connection */
812  openvpn_snprintf(buf, sizeof(buf), "Proxy-Connection: Keep-Alive");
813  if (!send_line_crlf(sd, buf))
814  {
815  goto error;
816  }
817 
818  /* send HOST etc, */
819  if (!add_proxy_headers(p, sd, host, port))
820  {
821  goto error;
822  }
823 
824  msg(D_PROXY, "Attempting NTLM Proxy-Authorization phase 3");
825  {
826  const char *np3 = ntlm_phase_3(p, buf2, &gc);
827  if (!np3)
828  {
829  msg(D_PROXY, "NTLM Proxy-Authorization phase 3 failed: received corrupted data from proxy server");
830  goto error;
831  }
832  openvpn_snprintf(buf, sizeof(buf), "Proxy-Authorization: NTLM %s", np3);
833  }
834 
835  msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
836  if (!send_line_crlf(sd, buf))
837  {
838  goto error;
839  }
840  /* ok so far... */
841  /* send empty CR, LF */
842  if (!send_crlf(sd))
843  {
844  goto error;
845  }
846 
847  /* receive reply from proxy */
848  if (!recv_line(sd, buf, sizeof(buf), get_server_poll_remaining_time(server_poll_timeout), true, NULL, 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  openvpn_snprintf(uri, sizeof(uri), "%s:%s",
903  host,
904  port);
905 
906  if (opaque)
907  {
908  const int len = strlen(opaque)+16;
909  opaque_kv = gc_malloc(len, false, &gc);
910  openvpn_snprintf(opaque_kv, len, ", opaque=\"%s\"", opaque);
911  }
912 
913  DigestCalcHA1(algor,
914  username,
915  realm,
916  password,
917  nonce,
918  (char *)cnonce,
919  session_key);
921  nonce,
922  nonce_count,
923  (char *)cnonce,
924  qop,
925  http_method,
926  uri,
927  NULL,
928  response);
929 
930  /* format HTTP CONNECT message */
931  openvpn_snprintf(buf, sizeof(buf), "%s %s HTTP/%s",
932  http_method,
933  uri,
934  p->options.http_version);
935 
936  msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
937 
938  /* send HTTP CONNECT message to proxy */
939  if (!send_line_crlf(sd, buf))
940  {
941  goto error;
942  }
943 
944  /* send HOST etc, */
945  if (!add_proxy_headers(p, sd, host, port))
946  {
947  goto error;
948  }
949 
950  /* send digest response */
951  openvpn_snprintf(buf, sizeof(buf), "Proxy-Authorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", qop=%s, nc=%s, cnonce=\"%s\", response=\"%s\"%s",
952  username,
953  realm,
954  nonce,
955  uri,
956  qop,
957  nonce_count,
958  cnonce,
959  response,
960  opaque_kv
961  );
962  msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
963  if (!send_line_crlf(sd, buf))
964  {
965  goto error;
966  }
967  if (!send_crlf(sd))
968  {
969  goto error;
970  }
971 
972  /* receive reply from proxy */
973  if (!recv_line(sd, buf, sizeof(buf), get_server_poll_remaining_time(server_poll_timeout), true, NULL, signal_received))
974  {
975  goto error;
976  }
977 
978  /* remove trailing CR, LF */
979  chomp(buf);
980 
981  msg(D_PROXY, "HTTP proxy returned: '%s'", buf);
982 
983  /* parse return string */
984  nparms = sscanf(buf, "%*s %d", &status);
985  processed = true;
986  }
987  else
988  {
989  msg(D_PROXY, "HTTP proxy: digest method not supported");
990  goto error;
991  }
992  }
993 #endif /* if PROXY_DIGEST_AUTH */
994  else if (p->options.auth_retry)
995  {
996  /* figure out what kind of authentication the proxy needs */
997  char *pa = NULL;
998  const int method = get_proxy_authenticate(sd,
999  get_server_poll_remaining_time(server_poll_timeout),
1000  &pa,
1001  signal_received);
1002  if (method != HTTP_AUTH_NONE)
1003  {
1004  if (pa)
1005  {
1006  msg(D_PROXY, "HTTP proxy authenticate '%s'", pa);
1007  }
1008  if (p->options.auth_retry == PAR_NCT && method == HTTP_AUTH_BASIC)
1009  {
1010  msg(D_PROXY, "HTTP proxy: support for basic auth and other cleartext proxy auth methods is disabled");
1011  free(pa);
1012  goto error;
1013  }
1014  p->auth_method = method;
1015  store_proxy_authenticate(p, pa);
1016  ret = true;
1017  goto done;
1018  }
1019  else
1020  {
1021  msg(D_PROXY, "HTTP proxy: do not recognize the authentication method required by proxy");
1022  free(pa);
1023  goto error;
1024  }
1025  }
1026  else
1027  {
1028  if (!processed)
1029  {
1030  msg(D_PROXY, "HTTP proxy: no support for proxy authentication method");
1031  }
1032  goto error;
1033  }
1034 
1035  /* clear state */
1036  if (p->options.auth_retry)
1037  {
1039  }
1040  store_proxy_authenticate(p, NULL);
1041  }
1042 
1043  /* check return code, success = 200 */
1044  if (nparms < 1 || status != 200)
1045  {
1046  msg(D_LINK_ERRORS, "HTTP proxy returned bad status");
1047 #if 0
1048  /* DEBUGGING -- show a multi-line HTTP error response */
1049  dump_residual(sd, get_server_poll_remaining_time(server_poll_timeout), signal_received);
1050 #endif
1051  goto error;
1052  }
1053 
1054  /* SUCCESS */
1055 
1056  /* receive line from proxy and discard */
1057  if (!recv_line(sd, NULL, 0, get_server_poll_remaining_time(server_poll_timeout), true, NULL, signal_received))
1058  {
1059  goto error;
1060  }
1061 
1062  /*
1063  * Toss out any extraneous chars, but don't throw away the
1064  * start of the OpenVPN data stream (put it in lookahead).
1065  */
1066  while (recv_line(sd, NULL, 0, 2, false, lookahead, signal_received))
1067  {
1068  }
1069 
1070  /* reset queried_creds so that we don't think that the next creds request is due to an auth error */
1071  p->queried_creds = false;
1072 
1073 #if 0
1074  if (lookahead && BLEN(lookahead))
1075  {
1076  msg(M_INFO, "HTTP PROXY: lookahead: %s", format_hex(BPTR(lookahead), BLEN(lookahead), 0));
1077  }
1078 #endif
1079 
1080 done:
1081  gc_free(&gc);
1082  return ret;
1083 
1084 error:
1085  register_signal(sig_info, SIGUSR1, "HTTP proxy error"); /* SOFT-SIGUSR1 -- HTTP proxy error */
1086  gc_free(&gc);
1087  return ret;
1088 }
signal_info::signal_received
volatile int signal_received
Definition: sig.h:43
DigestCalcResponse
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
make_base64_string2
uint8_t * make_base64_string2(const uint8_t *str, int src_len, struct gc_arena *gc)
Definition: proxy.c:227
HTTP_AUTH_NTLM2
#define HTTP_AUTH_NTLM2
Definition: proxy.h:35
static_proxy_user_pass
static struct user_pass static_proxy_user_pass
Definition: proxy.c:60
http_proxy_options::auth_file
const char * auth_file
Definition: proxy.h:54
M_INFO
#define M_INFO
Definition: errlevel.h:55
GET_USER_PASS_PREVIOUS_CREDS_FAILED
#define GET_USER_PASS_PREVIOUS_CREDS_FAILED
Definition: misc.h:113
gc_new
static struct gc_arena gc_new(void)
Definition: buffer.h:1031
send_line_crlf
static bool send_line_crlf(socket_descriptor_t sd, const char *src)
Definition: proxy.c:207
M_ERRNO
#define M_ERRNO
Definition: error.h:100
forward.h
get_proxy_authenticate
static int get_proxy_authenticate(socket_descriptor_t sd, int timeout, char **data, volatile int *signal_received)
Definition: proxy.c:321
http_proxy_options::http_version
const char * http_version
Definition: proxy.h:56
PACKAGE_NAME
#define PACKAGE_NAME
Definition: config.h:492
http_proxy_info::defined
bool defined
Definition: proxy.h:69
D_LINK_ERRORS
#define D_LINK_ERRORS
Definition: errlevel.h:57
M_FATAL
#define M_FATAL
Definition: error.h:95
win32.h
http_custom_header::name
const char * name
Definition: proxy.h:39
buf_init
#define buf_init(buf, offset)
Definition: buffer.h:209
http_proxy_options::auth_file_up
const char * auth_file_up
Definition: proxy.h:55
BSTR
#define BSTR(buf)
Definition: buffer.h:129
user_pass::username
char username[USER_PASS_LEN]
Definition: misc.h:71
http_proxy_info
Definition: proxy.h:68
http_proxy_options::auth_method_string
const char * auth_method_string
Definition: proxy.h:53
alloc_buf_gc
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition: buffer.c:88
user_pass::defined
bool defined
Definition: misc.h:58
get_user_pass_http
static void get_user_pass_http(struct http_proxy_info *p, const bool force)
Definition: proxy.c:260
openvpn_base64_encode
int openvpn_base64_encode(const void *data, int size, char **str)
Definition: base64.c:52
dmsg
#define dmsg(flags,...)
Definition: error.h:154
ntlm.h
http_proxy_info::options
struct http_proxy_options options
Definition: proxy.h:71
fdmisc.h
DigestCalcHA1
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
D_PROXY
#define D_PROXY
Definition: errlevel.h:74
http_proxy_info::auth_method
int auth_method
Definition: proxy.h:70
GET_USER_PASS_MANAGEMENT
#define GET_USER_PASS_MANAGEMENT
Definition: misc.h:107
http_proxy_options::inline_creds
bool inline_creds
Definition: proxy.h:59
key
Container for unidirectional cipher and HMAC key material.
Definition: crypto.h:149
establish_http_proxy_passthru
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:637
get_server_poll_remaining_time
int get_server_poll_remaining_time(struct event_timeout *server_poll_timeout)
Definition: forward.c:496
CLEAR
#define CLEAR(x)
Definition: basic.h:33
string_alloc
char * string_alloc(const char *str, struct gc_arena *gc)
Definition: buffer.c:693
ASSERT
#define ASSERT(x)
Definition: error.h:201
store_proxy_authenticate
static void store_proxy_authenticate(struct http_proxy_info *p, char *data)
Definition: proxy.c:370
MAX_CUSTOM_HTTP_HEADER
#define MAX_CUSTOM_HTTP_HEADER
Definition: proxy.h:43
http_proxy_options::user_agent
const char * user_agent
Definition: proxy.h:57
http_proxy_options::auth_retry
int auth_retry
Definition: proxy.h:51
BLEN
#define BLEN(buf)
Definition: buffer.h:127
purge_user_pass
void purge_user_pass(struct user_pass *up, const bool force)
Definition: misc.c:473
send_crlf
static bool send_crlf(socket_descriptor_t sd)
Definition: proxy.c:221
buf_write_u8
static bool buf_write_u8(struct buffer *dest, uint8_t data)
Definition: buffer.h:710
HTTP_AUTH_DIGEST
#define HTTP_AUTH_DIGEST
Definition: proxy.h:33
UP_TYPE_PROXY
#define UP_TYPE_PROXY
Definition: proxy.c:43
misc.h
M_WARN
#define M_WARN
Definition: error.h:97
ALLOC_OBJ_CLEAR_GC
#define ALLOC_OBJ_CLEAR_GC(dptr, type, gc)
Definition: buffer.h:1103
openvpn_fd_set
static void openvpn_fd_set(socket_descriptor_t fd, fd_set *setp)
Definition: fdmisc.h:40
http_proxy_options::port
const char * port
Definition: proxy.h:46
crypto.h
base64.h
get_user_pass
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:147
send_line
static bool send_line(socket_descriptor_t sd, const char *buf)
Definition: proxy.c:194
buffer
Wrapper structure for dynamically allocated memory.
Definition: buffer.h:60
httpdigest.h
http_proxy_options::server
const char * server
Definition: proxy.h:45
rand_bytes
int rand_bytes(uint8_t *output, int len)
Wrapper for secure random number generator.
Definition: crypto_openssl.c:571
buf_write
static bool buf_write(struct buffer *dest, const void *src, size_t size)
Definition: buffer.h:686
init_http_proxy_options_once
struct http_proxy_options * init_http_proxy_options_once(struct http_proxy_options **hpo, struct gc_arena *gc)
Definition: proxy.c:46
proxy.h
http-client.session_key
session_key
Definition: http-client.py:8
syshead.h
http_proxy_info::proxy_authenticate
char * proxy_authenticate
Definition: proxy.h:73
BPTR
#define BPTR(buf)
Definition: buffer.h:124
http_proxy_info::queried_creds
bool queried_creds
Definition: proxy.h:74
gc_arena
Garbage collection arena used to keep track of dynamically allocated memory.
Definition: buffer.h:116
recv_line
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
free_buf
void free_buf(struct buffer *buf)
Definition: buffer.c:183
HTTP_AUTH_BASIC
#define HTTP_AUTH_BASIC
Definition: proxy.h:32
socket_descriptor_t
SOCKET socket_descriptor_t
Definition: syshead.h:429
common.h
get_pa_var
static char * get_pa_var(const char *key, const char *pa, struct gc_arena *gc)
Definition: proxy.c:462
chomp
void chomp(char *str)
Definition: buffer.c:658
clear_user_pass_http
static void clear_user_pass_http(void)
Definition: proxy.c:254
username_password_as_base64
static const char * username_password_as_base64(const struct http_proxy_info *p, struct gc_arena *gc)
Definition: proxy.c:244
gc_malloc
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Definition: buffer.c:380
HTTP_AUTH_NONE
#define HTTP_AUTH_NONE
Definition: proxy.h:31
ntlm_phase_3
const char * ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_arena *gc)
Definition: ntlm.c:192
signal_info
Definition: sig.h:41
openvpn_snprintf
bool openvpn_snprintf(char *str, size_t size, const char *format,...)
Definition: buffer.c:294
status
static SERVICE_STATUS status
Definition: interactive.c:52
gc_free
static void gc_free(struct gc_arena *a)
Definition: buffer.h:1039
add_proxy_headers
static bool add_proxy_headers(struct http_proxy_info *p, socket_descriptor_t sd, const char *host, const char *port)
Definition: proxy.c:566
socket.h
ALLOC_OBJ_CLEAR
#define ALLOC_OBJ_CLEAR(dptr, type)
Definition: buffer.h:1066
config.h
http_proxy_options
Definition: proxy.h:44
get_key_value
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:381
event_timeout
Definition: interval.h:136
format_hex
static char * format_hex(const uint8_t *data, int size, int maxoutput, struct gc_arena *gc)
Definition: buffer.h:523
D_SHOW_KEYS
#define D_SHOW_KEYS
Definition: errlevel.h:121
user_pass::password
char password[USER_PASS_LEN]
Definition: misc.h:72
get_signal
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
GET_USER_PASS_INLINE_CREDS
#define GET_USER_PASS_INLINE_CREDS
Definition: misc.h:119
MSG_NOSIGNAL
#define MSG_NOSIGNAL
Definition: socket.h:254
ntlm_phase_1
const char * ntlm_phase_1(const struct http_proxy_info *p, struct gc_arena *gc)
Definition: ntlm.c:175
PAR_NCT
#define PAR_NCT
Definition: proxy.h:50
make_base64_string
uint8_t * make_base64_string(const uint8_t *str, struct gc_arena *gc)
Definition: proxy.c:238
http_proxy_info::up
struct user_pass up
Definition: proxy.h:72
register_signal
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
http_custom_header::content
const char * content
Definition: proxy.h:40
user_pass
Definition: misc.h:56
alloc_buf
struct buffer alloc_buf(size_t size)
Definition: buffer.c:62
memdbg.h
http_proxy_new
struct http_proxy_info * http_proxy_new(const struct http_proxy_options *o)
Definition: proxy.c:496
msg
#define msg(flags,...)
Definition: error.h:150
http_proxy_options::custom_headers
struct http_custom_header custom_headers[MAX_CUSTOM_HTTP_HEADER]
Definition: proxy.h:58
buf_defined
static bool buf_defined(const struct buffer *buf)
Definition: buffer.h:228
buf_printf
bool buf_printf(struct buffer *buf, const char *format,...)
Definition: buffer.c:240
http_proxy_close
void http_proxy_close(struct http_proxy_info *hp)
Definition: proxy.c:560
buffer::data
uint8_t * data
Pointer to the allocated memory.
Definition: buffer.h:68