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-2018 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 #elif defined(_MSC_VER)
27 #include "config-msvc.h"
28 #endif
29 
30 #include "syshead.h"
31 
32 #include "common.h"
33 #include "misc.h"
34 #include "crypto.h"
35 #include "win32.h"
36 #include "socket.h"
37 #include "fdmisc.h"
38 #include "proxy.h"
39 #include "base64.h"
40 #include "httpdigest.h"
41 #include "ntlm.h"
42 #include "memdbg.h"
43 #include "forward.h"
44 
45 #define UP_TYPE_PROXY "HTTP Proxy"
46 
47 struct http_proxy_options *
49  struct gc_arena *gc)
50 {
51  if (!*hpo)
52  {
53  ALLOC_OBJ_CLEAR_GC(*hpo, struct http_proxy_options, gc);
54  /* http proxy defaults */
55  (*hpo)->http_version = "1.0";
56  }
57  return *hpo;
58 }
59 
60 
61 /* cached proxy username/password */
63 
64 static bool
66  char *buf,
67  int len,
68  const int timeout_sec,
69  const bool verbose,
70  struct buffer *lookahead,
71  volatile int *signal_received)
72 {
73  struct buffer la;
74  int lastc = 0;
75 
76  CLEAR(la);
77  if (lookahead)
78  {
79  la = *lookahead;
80  }
81 
82  while (true)
83  {
84  int status;
85  ssize_t size;
86  fd_set reads;
87  struct timeval tv;
88  uint8_t c;
89 
90  if (buf_defined(&la))
91  {
92  ASSERT(buf_init(&la, 0));
93  }
94 
95  FD_ZERO(&reads);
96  openvpn_fd_set(sd, &reads);
97  tv.tv_sec = timeout_sec;
98  tv.tv_usec = 0;
99 
100  status = select(sd + 1, &reads, NULL, NULL, &tv);
101 
102  get_signal(signal_received);
103  if (*signal_received)
104  {
105  goto error;
106  }
107 
108  /* timeout? */
109  if (status == 0)
110  {
111  if (verbose)
112  {
113  msg(D_LINK_ERRORS | M_ERRNO, "recv_line: TCP port read timeout expired");
114  }
115  goto error;
116  }
117 
118  /* error */
119  if (status < 0)
120  {
121  if (verbose)
122  {
123  msg(D_LINK_ERRORS | M_ERRNO, "recv_line: TCP port read failed on select()");
124  }
125  goto error;
126  }
127 
128  /* read single char */
129  size = recv(sd, &c, 1, MSG_NOSIGNAL);
130 
131  /* error? */
132  if (size != 1)
133  {
134  if (verbose)
135  {
136  msg(D_LINK_ERRORS | M_ERRNO, "recv_line: TCP port read failed on recv()");
137  }
138  goto error;
139  }
140 
141 #if 0
142  if (isprint(c))
143  {
144  msg(M_INFO, "PROXY: read '%c' (%d)", c, (int)c);
145  }
146  else
147  {
148  msg(M_INFO, "PROXY: read (%d)", (int)c);
149  }
150 #endif
151 
152  /* store char in buffer */
153  if (len > 1)
154  {
155  *buf++ = c;
156  --len;
157  }
158 
159  /* also store char in lookahead buffer */
160  if (buf_defined(&la))
161  {
162  buf_write_u8(&la, c);
163  if (!isprint(c) && !isspace(c)) /* not ascii? */
164  {
165  if (verbose)
166  {
167  msg(D_LINK_ERRORS | M_ERRNO, "recv_line: Non-ASCII character (%d) read on recv()", (int)c);
168  }
169  *lookahead = la;
170  return false;
171  }
172  }
173 
174  /* end of line? */
175  if (lastc == '\r' && c == '\n')
176  {
177  break;
178  }
179 
180  lastc = c;
181  }
182 
183  /* append trailing null */
184  if (len > 0)
185  {
186  *buf++ = '\0';
187  }
188 
189  return true;
190 
191 error:
192  return false;
193 }
194 
195 static bool
197  const char *buf)
198 {
199  const ssize_t size = send(sd, buf, strlen(buf), MSG_NOSIGNAL);
200  if (size != (ssize_t) strlen(buf))
201  {
202  msg(D_LINK_ERRORS | M_ERRNO, "send_line: TCP port write failed on send()");
203  return false;
204  }
205  return true;
206 }
207 
208 static bool
210  const char *src)
211 {
212  bool ret;
213 
214  struct buffer buf = alloc_buf(strlen(src) + 3);
215  ASSERT(buf_write(&buf, src, strlen(src)));
216  ASSERT(buf_write(&buf, "\r\n", 3));
217  ret = send_line(sd, BSTR(&buf));
218  free_buf(&buf);
219  return ret;
220 }
221 
222 static bool
224 {
225  return send_line_crlf(sd, "");
226 }
227 
228 uint8_t *
229 make_base64_string2(const uint8_t *str, int src_len, struct gc_arena *gc)
230 {
231  uint8_t *ret = NULL;
232  char *b64out = NULL;
233  ASSERT(openvpn_base64_encode((const void *)str, src_len, &b64out) >= 0);
234  ret = (uint8_t *) string_alloc(b64out, gc);
235  free(b64out);
236  return ret;
237 }
238 
239 uint8_t *
240 make_base64_string(const uint8_t *str, struct gc_arena *gc)
241 {
242  return make_base64_string2(str, strlen((const char *)str), gc);
243 }
244 
245 static const char *
247  struct gc_arena *gc)
248 {
249  struct buffer out = alloc_buf_gc(strlen(p->up.username) + strlen(p->up.password) + 2, gc);
250  ASSERT(strlen(p->up.username) > 0);
251  buf_printf(&out, "%s:%s", p->up.username, p->up.password);
252  return (const char *)make_base64_string((const uint8_t *)BSTR(&out), gc);
253 }
254 
255 static void
257 {
259 }
260 
261 static void
262 get_user_pass_http(struct http_proxy_info *p, const bool force)
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  if (p->queried_creds)
277  {
279  }
280  if (p->options.inline_creds)
281  {
283  }
285  p->options.auth_file,
287  flags);
288  p->queried_creds = true;
290  }
291 }
292 
293 #if 0
294 /* function only used in #if 0 debug statement */
295 static void
296 dump_residual(socket_descriptor_t sd,
297  int timeout,
298  volatile int *signal_received)
299 {
300  char buf[256];
301  while (true)
302  {
303  if (!recv_line(sd, buf, sizeof(buf), timeout, true, NULL, signal_received))
304  {
305  return;
306  }
307  chomp(buf);
308  msg(D_PROXY, "PROXY HEADER: '%s'", buf);
309  }
310 }
311 #endif
312 
313 /*
314  * Extract the Proxy-Authenticate header from the stream.
315  * Consumes all headers.
316  */
317 static int
319  int timeout,
320  char **data,
321  volatile int *signal_received)
322 {
323  char buf[256];
324  int ret = HTTP_AUTH_NONE;
325  while (true)
326  {
327  if (!recv_line(sd, buf, sizeof(buf), timeout, true, NULL, signal_received))
328  {
329  free(*data);
330  *data = NULL;
331  return HTTP_AUTH_NONE;
332  }
333  chomp(buf);
334  if (!strlen(buf))
335  {
336  return ret;
337  }
338  if (ret == HTTP_AUTH_NONE && !strncmp(buf, "Proxy-Authenticate: ", 20))
339  {
340  if (!strncmp(buf+20, "Basic ", 6))
341  {
342  msg(D_PROXY, "PROXY AUTH BASIC: '%s'", buf);
343  *data = string_alloc(buf+26, NULL);
344  ret = HTTP_AUTH_BASIC;
345  }
346 #if PROXY_DIGEST_AUTH
347  else if (!strncmp(buf+20, "Digest ", 7))
348  {
349  msg(D_PROXY, "PROXY AUTH DIGEST: '%s'", buf);
350  *data = string_alloc(buf+27, NULL);
351  ret = HTTP_AUTH_DIGEST;
352  }
353 #endif
354 #if NTLM
355  else if (!strncmp(buf+20, "NTLM", 4))
356  {
357  msg(D_PROXY, "PROXY AUTH HTLM: '%s'", buf);
358  *data = NULL;
359  ret = HTTP_AUTH_NTLM;
360  }
361 #endif
362  }
363  }
364 }
365 
366 static void
368 {
369  if (p->proxy_authenticate)
370  {
372  }
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  {
526  }
527  else if (!strcmp(o->auth_method_string, "ntlm2"))
528  {
530  }
531 #endif
532  else
533  {
534  msg(M_FATAL, "ERROR: unknown HTTP authentication method: '%s'",
535  o->auth_method_string);
536  }
537  }
538 
539  /* only basic and NTLM/NTLMv2 authentication supported so far */
541  {
542  get_user_pass_http(p, true);
543  }
544 
545 #if !NTLM
547  {
548  msg(M_FATAL, "Sorry, this version of " PACKAGE_NAME " was built without NTLM Proxy support.");
549  }
550 #endif
551 
552  p->defined = true;
553  return p;
554 }
555 
556 void
558 {
559  free(hp);
560 }
561 
562 static bool
564  socket_descriptor_t sd, /* already open to proxy */
565  const char *host, /* openvpn server remote */
566  const char *port /* openvpn server port */
567  )
568 {
569  char buf[512];
570  int i;
571  bool host_header_sent = false;
572 
573  /*
574  * Send custom headers if provided
575  * If content is NULL the whole header is in name
576  * Also remember if we already sent a Host: header
577  */
578  for (i = 0; i < MAX_CUSTOM_HTTP_HEADER && p->options.custom_headers[i].name; i++)
579  {
580  if (p->options.custom_headers[i].content)
581  {
582  openvpn_snprintf(buf, sizeof(buf), "%s: %s",
585  if (!strcasecmp(p->options.custom_headers[i].name, "Host"))
586  {
587  host_header_sent = true;
588  }
589  }
590  else
591  {
592  openvpn_snprintf(buf, sizeof(buf), "%s",
593  p->options.custom_headers[i].name);
594  if (!strncasecmp(p->options.custom_headers[i].name, "Host:", 5))
595  {
596  host_header_sent = true;
597  }
598  }
599 
600  msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
601  if (!send_line_crlf(sd, buf))
602  {
603  return false;
604  }
605  }
606 
607  if (!host_header_sent)
608  {
609  openvpn_snprintf(buf, sizeof(buf), "Host: %s", host);
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  /* send User-Agent string if provided */
618  if (p->options.user_agent)
619  {
620  openvpn_snprintf(buf, sizeof(buf), "User-Agent: %s",
621  p->options.user_agent);
622  msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
623  if (!send_line_crlf(sd, buf))
624  {
625  return false;
626  }
627  }
628 
629  return true;
630 }
631 
632 
633 bool
635  socket_descriptor_t sd, /* already open to proxy */
636  const char *host, /* openvpn server remote */
637  const char *port, /* openvpn server port */
638  struct event_timeout *server_poll_timeout,
639  struct buffer *lookahead,
640  volatile int *signal_received)
641 {
642  struct gc_arena gc = gc_new();
643  char buf[512];
644  char buf2[129];
645  char get[80];
646  int status;
647  int nparms;
648  bool ret = false;
649  bool processed = false;
650 
651  /* get user/pass if not previously given */
652  if (p->auth_method == HTTP_AUTH_BASIC
654  || p->auth_method == HTTP_AUTH_NTLM)
655  {
656  get_user_pass_http(p, false);
657  }
658 
659  /* are we being called again after getting the digest server nonce in the previous transaction? */
661  {
662  nparms = 1;
663  status = 407;
664  }
665  else
666  {
667  /* format HTTP CONNECT message */
668  openvpn_snprintf(buf, sizeof(buf), "CONNECT %s:%s HTTP/%s",
669  host,
670  port,
671  p->options.http_version);
672 
673  msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
674 
675  /* send HTTP CONNECT message to proxy */
676  if (!send_line_crlf(sd, buf))
677  {
678  goto error;
679  }
680 
681  if (!add_proxy_headers(p, sd, host, port))
682  {
683  goto error;
684  }
685 
686  /* auth specified? */
687  switch (p->auth_method)
688  {
689  case HTTP_AUTH_NONE:
690  break;
691 
692  case HTTP_AUTH_BASIC:
693  openvpn_snprintf(buf, sizeof(buf), "Proxy-Authorization: Basic %s",
695  msg(D_PROXY, "Attempting Basic Proxy-Authorization");
696  dmsg(D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf);
697  if (!send_line_crlf(sd, buf))
698  {
699  goto error;
700  }
701  break;
702 
703 #if NTLM
704  case HTTP_AUTH_NTLM:
705  case HTTP_AUTH_NTLM2:
706  /* keep-alive connection */
707  openvpn_snprintf(buf, sizeof(buf), "Proxy-Connection: Keep-Alive");
708  if (!send_line_crlf(sd, buf))
709  {
710  goto error;
711  }
712 
713  openvpn_snprintf(buf, sizeof(buf), "Proxy-Authorization: NTLM %s",
714  ntlm_phase_1(p, &gc));
715  msg(D_PROXY, "Attempting NTLM Proxy-Authorization phase 1");
716  dmsg(D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf);
717  if (!send_line_crlf(sd, buf))
718  {
719  goto error;
720  }
721  break;
722 #endif
723 
724  default:
725  ASSERT(0);
726  }
727 
728  /* send empty CR, LF */
729  if (!send_crlf(sd))
730  {
731  goto error;
732  }
733 
734  /* receive reply from proxy */
735  if (!recv_line(sd, buf, sizeof(buf), get_server_poll_remaining_time(server_poll_timeout), true, NULL, signal_received))
736  {
737  goto error;
738  }
739 
740  /* remove trailing CR, LF */
741  chomp(buf);
742 
743  msg(D_PROXY, "HTTP proxy returned: '%s'", buf);
744 
745  /* parse return string */
746  nparms = sscanf(buf, "%*s %d", &status);
747 
748  }
749 
750  /* check for a "407 Proxy Authentication Required" response */
751  while (nparms >= 1 && status == 407)
752  {
753  msg(D_PROXY, "Proxy requires authentication");
754 
755  if (p->auth_method == HTTP_AUTH_BASIC && !processed)
756  {
757  processed = true;
758  }
759  else if ((p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) && !processed) /* check for NTLM */
760  {
761 #if NTLM
762  /* look for the phase 2 response */
763 
764  while (true)
765  {
766  if (!recv_line(sd, buf, sizeof(buf), get_server_poll_remaining_time(server_poll_timeout), true, NULL, signal_received))
767  {
768  goto error;
769  }
770  chomp(buf);
771  msg(D_PROXY, "HTTP proxy returned: '%s'", buf);
772 
773  openvpn_snprintf(get, sizeof get, "%%*s NTLM %%%ds", (int) sizeof(buf2) - 1);
774  nparms = sscanf(buf, get, buf2);
775  buf2[128] = 0; /* we only need the beginning - ensure it's null terminated. */
776 
777  /* check for "Proxy-Authenticate: NTLM TlRM..." */
778  if (nparms == 1)
779  {
780  /* parse buf2 */
781  msg(D_PROXY, "auth string: '%s'", buf2);
782  break;
783  }
784  }
785  /* if we are here then auth string was got */
786  msg(D_PROXY, "Received NTLM Proxy-Authorization phase 2 response");
787 
788  /* receive and discard everything else */
789  while (recv_line(sd, NULL, 0, 2, true, NULL, signal_received))
790  {
791  }
792 
793  /* now send the phase 3 reply */
794 
795  /* format HTTP CONNECT message */
796  openvpn_snprintf(buf, sizeof(buf), "CONNECT %s:%s HTTP/%s",
797  host,
798  port,
799  p->options.http_version);
800 
801  msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
802 
803  /* send HTTP CONNECT message to proxy */
804  if (!send_line_crlf(sd, buf))
805  {
806  goto error;
807  }
808 
809  /* keep-alive connection */
810  openvpn_snprintf(buf, sizeof(buf), "Proxy-Connection: Keep-Alive");
811  if (!send_line_crlf(sd, buf))
812  {
813  goto error;
814  }
815 
816  /* send HOST etc, */
817  if (!add_proxy_headers(p, sd, host, port))
818  {
819  goto error;
820  }
821 
822  msg(D_PROXY, "Attempting NTLM Proxy-Authorization phase 3");
823  {
824  const char *np3 = ntlm_phase_3(p, buf2, &gc);
825  if (!np3)
826  {
827  msg(D_PROXY, "NTLM Proxy-Authorization phase 3 failed: received corrupted data from proxy server");
828  goto error;
829  }
830  openvpn_snprintf(buf, sizeof(buf), "Proxy-Authorization: NTLM %s", np3);
831  }
832 
833  msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
834  if (!send_line_crlf(sd, buf))
835  {
836  goto error;
837  }
838  /* ok so far... */
839  /* send empty CR, LF */
840  if (!send_crlf(sd))
841  {
842  goto error;
843  }
844 
845  /* receive reply from proxy */
846  if (!recv_line(sd, buf, sizeof(buf), get_server_poll_remaining_time(server_poll_timeout), true, NULL, signal_received))
847  {
848  goto error;
849  }
850 
851  /* remove trailing CR, LF */
852  chomp(buf);
853 
854  msg(D_PROXY, "HTTP proxy returned: '%s'", buf);
855 
856  /* parse return string */
857  nparms = sscanf(buf, "%*s %d", &status);
858  processed = true;
859 #endif /* if NTLM */
860  }
861 #if PROXY_DIGEST_AUTH
862  else if (p->auth_method == HTTP_AUTH_DIGEST && !processed)
863  {
864  char *pa = p->proxy_authenticate;
865  const int method = p->auth_method;
866  ASSERT(pa);
867 
868  if (method == HTTP_AUTH_DIGEST)
869  {
870  const char *http_method = "CONNECT";
871  const char *nonce_count = "00000001";
872  const char *qop = "auth";
873  const char *username = p->up.username;
874  const char *password = p->up.password;
875  char *opaque_kv = "";
876  char uri[128];
877  uint8_t cnonce_raw[8];
878  uint8_t *cnonce;
879  HASHHEX session_key;
880  HASHHEX response;
881 
882  const char *realm = get_pa_var("realm", pa, &gc);
883  const char *nonce = get_pa_var("nonce", pa, &gc);
884  const char *algor = get_pa_var("algorithm", pa, &gc);
885  const char *opaque = get_pa_var("opaque", pa, &gc);
886 
887  if (!realm || !nonce)
888  {
889  msg(D_LINK_ERRORS, "HTTP proxy: digest auth failed, malformed response "
890  "from server: realm= or nonce= missing" );
891  goto error;
892  }
893 
894  /* generate a client nonce */
895  ASSERT(rand_bytes(cnonce_raw, sizeof(cnonce_raw)));
896  cnonce = make_base64_string2(cnonce_raw, sizeof(cnonce_raw), &gc);
897 
898 
899  /* build the digest response */
900  openvpn_snprintf(uri, sizeof(uri), "%s:%s",
901  host,
902  port);
903 
904  if (opaque)
905  {
906  const int len = strlen(opaque)+16;
907  opaque_kv = gc_malloc(len, false, &gc);
908  openvpn_snprintf(opaque_kv, len, ", opaque=\"%s\"", opaque);
909  }
910 
911  DigestCalcHA1(algor,
912  username,
913  realm,
914  password,
915  nonce,
916  (char *)cnonce,
917  session_key);
918  DigestCalcResponse(session_key,
919  nonce,
920  nonce_count,
921  (char *)cnonce,
922  qop,
923  http_method,
924  uri,
925  NULL,
926  response);
927 
928  /* format HTTP CONNECT message */
929  openvpn_snprintf(buf, sizeof(buf), "%s %s HTTP/%s",
930  http_method,
931  uri,
932  p->options.http_version);
933 
934  msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
935 
936  /* send HTTP CONNECT message to proxy */
937  if (!send_line_crlf(sd, buf))
938  {
939  goto error;
940  }
941 
942  /* send HOST etc, */
943  if (!add_proxy_headers(p, sd, host, port))
944  {
945  goto error;
946  }
947 
948  /* send digest response */
949  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",
950  username,
951  realm,
952  nonce,
953  uri,
954  qop,
955  nonce_count,
956  cnonce,
957  response,
958  opaque_kv
959  );
960  msg(D_PROXY, "Send to HTTP proxy: '%s'", buf);
961  if (!send_line_crlf(sd, buf))
962  {
963  goto error;
964  }
965  if (!send_crlf(sd))
966  {
967  goto error;
968  }
969 
970  /* receive reply from proxy */
971  if (!recv_line(sd, buf, sizeof(buf), get_server_poll_remaining_time(server_poll_timeout), true, NULL, signal_received))
972  {
973  goto error;
974  }
975 
976  /* remove trailing CR, LF */
977  chomp(buf);
978 
979  msg(D_PROXY, "HTTP proxy returned: '%s'", buf);
980 
981  /* parse return string */
982  nparms = sscanf(buf, "%*s %d", &status);
983  processed = true;
984  }
985  else
986  {
987  msg(D_PROXY, "HTTP proxy: digest method not supported");
988  goto error;
989  }
990  }
991 #endif /* if PROXY_DIGEST_AUTH */
992  else if (p->options.auth_retry)
993  {
994  /* figure out what kind of authentication the proxy needs */
995  char *pa = NULL;
996  const int method = get_proxy_authenticate(sd,
997  get_server_poll_remaining_time(server_poll_timeout),
998  &pa,
999  signal_received);
1000  if (method != HTTP_AUTH_NONE)
1001  {
1002  if (pa)
1003  {
1004  msg(D_PROXY, "HTTP proxy authenticate '%s'", pa);
1005  }
1006  if (p->options.auth_retry == PAR_NCT && method == HTTP_AUTH_BASIC)
1007  {
1008  msg(D_PROXY, "HTTP proxy: support for basic auth and other cleartext proxy auth methods is disabled");
1009  free(pa);
1010  goto error;
1011  }
1012  p->auth_method = method;
1013  store_proxy_authenticate(p, pa);
1014  ret = true;
1015  goto done;
1016  }
1017  else
1018  {
1019  msg(D_PROXY, "HTTP proxy: do not recognize the authentication method required by proxy");
1020  free(pa);
1021  goto error;
1022  }
1023  }
1024  else
1025  {
1026  if (!processed)
1027  {
1028  msg(D_PROXY, "HTTP proxy: no support for proxy authentication method");
1029  }
1030  goto error;
1031  }
1032 
1033  /* clear state */
1034  if (p->options.auth_retry)
1035  {
1037  }
1038  store_proxy_authenticate(p, NULL);
1039  }
1040 
1041  /* check return code, success = 200 */
1042  if (nparms < 1 || status != 200)
1043  {
1044  msg(D_LINK_ERRORS, "HTTP proxy returned bad status");
1045 #if 0
1046  /* DEBUGGING -- show a multi-line HTTP error response */
1047  dump_residual(sd, get_server_poll_remaining_time(server_poll_timeout), signal_received);
1048 #endif
1049  goto error;
1050  }
1051 
1052  /* SUCCESS */
1053 
1054  /* receive line from proxy and discard */
1055  if (!recv_line(sd, NULL, 0, get_server_poll_remaining_time(server_poll_timeout), true, NULL, signal_received))
1056  {
1057  goto error;
1058  }
1059 
1060  /*
1061  * Toss out any extraneous chars, but don't throw away the
1062  * start of the OpenVPN data stream (put it in lookahead).
1063  */
1064  while (recv_line(sd, NULL, 0, 2, false, lookahead, signal_received))
1065  {
1066  }
1067 
1068  /* reset queried_creds so that we don't think that the next creds request is due to an auth error */
1069  p->queried_creds = false;
1070 
1071 #if 0
1072  if (lookahead && BLEN(lookahead))
1073  {
1074  msg(M_INFO, "HTTP PROXY: lookahead: %s", format_hex(BPTR(lookahead), BLEN(lookahead), 0));
1075  }
1076 #endif
1077 
1078 done:
1079  gc_free(&gc);
1080  return ret;
1081 
1082 error:
1083  if (!*signal_received)
1084  {
1085  *signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- HTTP proxy error */
1086  }
1087  gc_free(&gc);
1088  return ret;
1089 }
static bool buf_write_u8(struct buffer *dest, int data)
Definition: buffer.h:713
struct http_proxy_info * http_proxy_new(const struct http_proxy_options *o)
Definition: proxy.c:496
#define MSG_NOSIGNAL
Definition: socket.h:256
const char * http_version
Definition: proxy.h:55
#define PAR_NCT
Definition: proxy.h:50
void free_buf(struct buffer *buf)
Definition: buffer.c:185
bool defined
Definition: proxy.h:68
char * string_alloc(const char *str, struct gc_arena *gc)
Definition: buffer.c:688
#define M_INFO
Definition: errlevel.h:55
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
static void gc_free(struct gc_arena *a)
Definition: buffer.h:1023
#define dmsg
Definition: error.h:174
const char * ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_arena *gc)
Definition: ntlm.c:192
#define UP_TYPE_PROXY
Definition: proxy.c:45
#define GET_USER_PASS_INLINE_CREDS
Definition: misc.h:124
static char * get_pa_var(const char *key, const char *pa, struct gc_arena *gc)
Definition: proxy.c:462
void http_proxy_close(struct http_proxy_info *hp)
Definition: proxy.c:557
#define HTTP_AUTH_BASIC
Definition: proxy.h:32
#define SIGUSR1
Definition: config-msvc.h:116
struct buffer alloc_buf(size_t size)
Definition: buffer.c:64
struct http_custom_header custom_headers[MAX_CUSTOM_HTTP_HEADER]
Definition: proxy.h:57
const char * content
Definition: proxy.h:40
int auth_method
Definition: proxy.h:69
#define HTTP_AUTH_NONE
Definition: proxy.h:31
bool buf_printf(struct buffer *buf, const char *format,...)
Definition: buffer.c:245
static char * format_hex(const uint8_t *data, int size, int maxoutput, struct gc_arena *gc)
Definition: buffer.h:526
bool defined
Definition: misc.h:64
const char * port
Definition: proxy.h:46
static void get_signal(volatile int *sig)
Definition: sig.h:92
const char * ntlm_phase_1(const struct http_proxy_info *p, struct gc_arena *gc)
Definition: ntlm.c:175
#define ASSERT(x)
Definition: error.h:221
#define strcasecmp
Definition: config-msvc.h:94
static void clear_user_pass_http(void)
Definition: proxy.c:256
char username[USER_PASS_LEN]
Definition: misc.h:74
const char * auth_method_string
Definition: proxy.h:53
static struct user_pass static_proxy_user_pass
Definition: proxy.c:62
struct http_proxy_options * init_http_proxy_options_once(struct http_proxy_options **hpo, struct gc_arena *gc)
Definition: proxy.c:48
list flags
#define GET_USER_PASS_PREVIOUS_CREDS_FAILED
Definition: misc.h:118
static bool buf_write(struct buffer *dest, const void *src, int size)
Definition: buffer.h:689
#define CLEAR(x)
Definition: basic.h:33
#define BPTR(buf)
Definition: buffer.h:124
bool openvpn_snprintf(char *str, size_t size, const char *format,...)
Definition: buffer.c:299
#define HTTP_AUTH_NTLM
Definition: proxy.h:34
uint8_t * make_base64_string(const uint8_t *str, struct gc_arena *gc)
Definition: proxy.c:240
int rand_bytes(uint8_t *output, int len)
Wrapper for secure random number generator.
static struct gc_arena gc_new(void)
Definition: buffer.h:1015
static void openvpn_fd_set(int fd, fd_set *setp)
Definition: fdmisc.h:40
bool inline_creds
Definition: proxy.h:58
void chomp(char *str)
Definition: buffer.c:653
#define PACKAGE_NAME
Definition: config.h:730
#define ALLOC_OBJ_CLEAR(dptr, type)
Definition: buffer.h:1050
static const char * username_password_as_base64(const struct http_proxy_info *p, struct gc_arena *gc)
Definition: proxy.c:246
int get_server_poll_remaining_time(struct event_timeout *server_poll_timeout)
Definition: forward.c:567
static void get_user_pass_http(struct http_proxy_info *p, const bool force)
Definition: proxy.c:262
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Definition: buffer.c:408
uint8_t * make_base64_string2(const uint8_t *str, int src_len, struct gc_arena *gc)
Definition: proxy.c:229
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:72
static SERVICE_STATUS status
Definition: automatic.c:43
#define M_ERRNO
Definition: error.h:99
#define msg
Definition: error.h:173
Interface functions to the internal and external multiplexers.
int openvpn_base64_encode(const void *data, int size, char **str)
Definition: base64.c:54
uint8_t * data
Pointer to the allocated memory.
Definition: buffer.h:68
const char * server
Definition: proxy.h:45
bool queried_creds
Definition: proxy.h:73
static void store_proxy_authenticate(struct http_proxy_info *p, char *data)
Definition: proxy.c:367
#define BLEN(buf)
Definition: buffer.h:127
#define MAX_CUSTOM_HTTP_HEADER
Definition: proxy.h:43
const char * user_agent
Definition: proxy.h:56
static bool get_user_pass(struct user_pass *up, const char *auth_file, const char *prefix, const unsigned int flags)
Definition: misc.h:133
static bool buf_defined(const struct buffer *buf)
Definition: buffer.h:215
unsigned __int8 uint8_t
Definition: config-msvc.h:123
char * proxy_authenticate
Definition: proxy.h:72
void purge_user_pass(struct user_pass *up, const bool force)
Definition: misc.c:459
#define strncasecmp
Definition: config-msvc.h:93
#define ALLOC_OBJ_CLEAR_GC(dptr, type, gc)
Definition: buffer.h:1087
const char * name
Definition: proxy.h:39
#define D_PROXY
Definition: errlevel.h:74
SOCKET socket_descriptor_t
Definition: syshead.h:488
Definition: misc.h:62
static bool add_proxy_headers(struct http_proxy_info *p, socket_descriptor_t sd, const char *host, const char *port)
Definition: proxy.c:563
Wrapper structure for dynamically allocated memory.
Definition: buffer.h:60
#define M_FATAL
Definition: error.h:94
#define buf_init(buf, offset)
Definition: buffer.h:196
#define HTTP_AUTH_NTLM2
Definition: proxy.h:35
#define D_SHOW_KEYS
Definition: errlevel.h:117
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:65
static int get_proxy_authenticate(socket_descriptor_t sd, int timeout, char **data, volatile int *signal_received)
Definition: proxy.c:318
static bool send_line(socket_descriptor_t sd, const char *buf)
Definition: proxy.c:196
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition: buffer.c:90
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, volatile int *signal_received)
Definition: proxy.c:634
#define free
Definition: cmocka.c:1850
Garbage collection arena used to keep track of dynamically allocated memory.
Definition: buffer.h:116
struct user_pass up
Definition: proxy.h:71
#define BSTR(buf)
Definition: buffer.h:129
static bool send_line_crlf(socket_descriptor_t sd, const char *src)
Definition: proxy.c:209
const char * auth_file
Definition: proxy.h:54
char password[USER_PASS_LEN]
Definition: misc.h:75
#define HTTP_AUTH_DIGEST
Definition: proxy.h:33
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:110
#define ssize_t
Definition: config-msvc.h:105
struct http_proxy_options options
Definition: proxy.h:70
static bool send_crlf(socket_descriptor_t sd)
Definition: proxy.c:223
#define D_LINK_ERRORS
Definition: errlevel.h:57
Container for unidirectional cipher and HMAC key material.
Definition: crypto.h:151
#define GET_USER_PASS_MANAGEMENT
Definition: misc.h:112