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-2010 OpenVPN Technologies, 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 20 * along with this program (see the file COPYING included with this 21 * distribution); if not, write to the Free Software Foundation, Inc., 22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 */ 24 25#ifdef HAVE_CONFIG_H 26#include "config.h" 27#elif defined(_MSC_VER) 28#include "config-msvc.h" 29#endif 30 31#include "syshead.h" 32 33#include "common.h" 34#include "misc.h" 35#include "crypto.h" 36#include "win32.h" 37#include "socket.h" 38#include "fdmisc.h" 39#include "proxy.h" 40#include "base64.h" 41#include "httpdigest.h" 42#include "ntlm.h" 43#include "memdbg.h" 44 45#ifdef ENABLE_HTTP_PROXY 46 47#define UP_TYPE_PROXY "HTTP Proxy" 48 49struct http_proxy_options * 50init_http_proxy_options_once (struct http_proxy_options **hpo, 51 struct gc_arena *gc) 52{ 53 if (!*hpo) 54 { 55 ALLOC_OBJ_CLEAR_GC (*hpo, struct http_proxy_options, gc); 56 /* http proxy defaults */ 57 (*hpo)->timeout = 5; 58 (*hpo)->http_version = "1.0"; 59 } 60 return *hpo; 61} 62 63 64/* cached proxy username/password */ 65static struct user_pass static_proxy_user_pass; 66 67static bool 68recv_line (socket_descriptor_t sd, 69 char *buf, 70 int len, 71 const int timeout_sec, 72 const bool verbose, 73 struct buffer *lookahead, 74 volatile int *signal_received) 75{ 76 struct buffer la; 77 int lastc = 0; 78 79 CLEAR (la); 80 if (lookahead) 81 la = *lookahead; 82 83 while (true) 84 { 85 int status; 86 ssize_t size; 87 fd_set reads; 88 struct timeval tv; 89 uint8_t c; 90 91 if (buf_defined (&la)) 92 { 93 ASSERT (buf_init (&la, 0)); 94 } 95 96 FD_ZERO (&reads); 97 FD_SET (sd, &reads); 98 tv.tv_sec = timeout_sec; 99 tv.tv_usec = 0; 100 101 status = select (sd + 1, &reads, NULL, NULL, &tv); 102 103 get_signal (signal_received); 104 if (*signal_received) 105 goto error; 106 107 /* timeout? */ 108 if (status == 0) 109 { 110 if (verbose) 111 msg (D_LINK_ERRORS | M_ERRNO, "recv_line: TCP port read timeout expired"); 112 goto error; 113 } 114 115 /* error */ 116 if (status < 0) 117 { 118 if (verbose) 119 msg (D_LINK_ERRORS | M_ERRNO, "recv_line: TCP port read failed on select()"); 120 goto error; 121 } 122 123 /* read single char */ 124 size = recv (sd, &c, 1, MSG_NOSIGNAL); 125 126 /* error? */ 127 if (size != 1) 128 { 129 if (verbose) 130 msg (D_LINK_ERRORS | M_ERRNO, "recv_line: TCP port read failed on recv()"); 131 goto error; 132 } 133 134#if 0 135 if (isprint(c)) 136 msg (M_INFO, "PROXY: read '%c' (%d)", c, (int)c); 137 else 138 msg (M_INFO, "PROXY: read (%d)", (int)c); 139#endif 140 141 /* store char in buffer */ 142 if (len > 1) 143 { 144 *buf++ = c; 145 --len; 146 } 147 148 /* also store char in lookahead buffer */ 149 if (buf_defined (&la)) 150 { 151 buf_write_u8 (&la, c); 152 if (!isprint(c) && !isspace(c)) /* not ascii? */ 153 { 154 if (verbose) 155 msg (D_LINK_ERRORS | M_ERRNO, "recv_line: Non-ASCII character (%d) read on recv()", (int)c); 156 *lookahead = la; 157 return false; 158 } 159 } 160 161 /* end of line? */ 162 if (lastc == '\r' && c == '\n') 163 break; 164 165 lastc = c; 166 } 167 168 /* append trailing null */ 169 if (len > 0) 170 *buf++ = '\0'; 171 172 return true; 173 174 error: 175 return false; 176} 177 178static bool 179send_line (socket_descriptor_t sd, 180 const char *buf) 181{ 182 const ssize_t size = send (sd, buf, strlen (buf), MSG_NOSIGNAL); 183 if (size != (ssize_t) strlen (buf)) 184 { 185 msg (D_LINK_ERRORS | M_ERRNO, "send_line: TCP port write failed on send()"); 186 return false; 187 } 188 return true; 189} 190 191static bool 192send_line_crlf (socket_descriptor_t sd, 193 const char *src) 194{ 195 bool ret; 196 197 struct buffer buf = alloc_buf (strlen (src) + 3); 198 ASSERT (buf_write (&buf, src, strlen (src))); 199 ASSERT (buf_write (&buf, "\r\n", 3)); 200 ret = send_line (sd, BSTR (&buf)); 201 free_buf (&buf); 202 return ret; 203} 204 205static bool 206send_crlf (socket_descriptor_t sd) 207{ 208 return send_line_crlf (sd, ""); 209} 210 211uint8_t * 212make_base64_string2 (const uint8_t *str, int src_len, struct gc_arena *gc) 213{ 214 uint8_t *ret = NULL; 215 char *b64out = NULL; 216 ASSERT (openvpn_base64_encode ((const void *)str, src_len, &b64out) >= 0); 217 ret = (uint8_t *) string_alloc (b64out, gc); 218 free (b64out); 219 return ret; 220} 221 222uint8_t * 223make_base64_string (const uint8_t *str, struct gc_arena *gc) 224{ 225 return make_base64_string2 (str, strlen ((const char *)str), gc); 226} 227 228static const char * 229username_password_as_base64 (const struct http_proxy_info *p, 230 struct gc_arena *gc) 231{ 232 struct buffer out = alloc_buf_gc (strlen (p->up.username) + strlen (p->up.password) + 2, gc); 233 ASSERT (strlen (p->up.username) > 0); 234 buf_printf (&out, "%s:%s", p->up.username, p->up.password); 235 return (const char *)make_base64_string ((const uint8_t*)BSTR (&out), gc); 236} 237 238static void 239get_user_pass_http (struct http_proxy_info *p, const bool force) 240{ 241 if (!static_proxy_user_pass.defined || force) 242 { 243 unsigned int flags = GET_USER_PASS_MANAGEMENT; 244 if (p->queried_creds) 245 flags |= GET_USER_PASS_PREVIOUS_CREDS_FAILED; 246 get_user_pass (&static_proxy_user_pass, 247 p->options.auth_file, 248 UP_TYPE_PROXY, 249 flags); 250 p->queried_creds = true; 251 p->up = static_proxy_user_pass; 252 } 253} 254static void 255clear_user_pass_http (void) 256{ 257 purge_user_pass (&static_proxy_user_pass, true); 258} 259 260static void 261dump_residual (socket_descriptor_t sd, 262 int timeout, 263 volatile int *signal_received) 264{ 265 char buf[256]; 266 while (true) 267 { 268 if (!recv_line (sd, buf, sizeof (buf), timeout, true, NULL, signal_received)) 269 return; 270 chomp (buf); 271 msg (D_PROXY, "PROXY HEADER: '%s'", buf); 272 } 273} 274 275/* 276 * Extract the Proxy-Authenticate header from the stream. 277 * Consumes all headers. 278 */ 279static int 280get_proxy_authenticate (socket_descriptor_t sd, 281 int timeout, 282 char **data, 283 struct gc_arena *gc, 284 volatile int *signal_received) 285{ 286 char buf[256]; 287 int ret = HTTP_AUTH_NONE; 288 while (true) 289 { 290 if (!recv_line (sd, buf, sizeof (buf), timeout, true, NULL, signal_received)) 291 { 292 *data = NULL; 293 return HTTP_AUTH_NONE; 294 } 295 chomp (buf); 296 if (!strlen(buf)) 297 return ret; 298 if (ret == HTTP_AUTH_NONE && !strncmp(buf, "Proxy-Authenticate: ", 20)) 299 { 300 if (!strncmp(buf+20, "Basic ", 6)) 301 { 302 msg (D_PROXY, "PROXY AUTH BASIC: '%s'", buf); 303 *data = string_alloc(buf+26, gc); 304 ret = HTTP_AUTH_BASIC; 305 } 306#if PROXY_DIGEST_AUTH 307 else if (!strncmp(buf+20, "Digest ", 7)) 308 { 309 msg (D_PROXY, "PROXY AUTH DIGEST: '%s'", buf); 310 *data = string_alloc(buf+27, gc); 311 ret = HTTP_AUTH_DIGEST; 312 } 313#endif 314#if NTLM 315 else if (!strncmp(buf+20, "NTLM", 4)) 316 { 317 msg (D_PROXY, "PROXY AUTH HTLM: '%s'", buf); 318 *data = NULL; 319 ret = HTTP_AUTH_NTLM; 320 } 321#endif 322 } 323 } 324} 325 326static void 327store_proxy_authenticate (struct http_proxy_info *p, char *data) 328{ 329 if (p->proxy_authenticate) 330 free (p->proxy_authenticate); 331 p->proxy_authenticate = data; 332} 333 334/* 335 * Parse out key/value pairs from Proxy-Authenticate string. 336 * Return true on success, or false on parse failure. 337 */ 338static bool 339get_key_value(const char *str, /* source string */ 340 char *key, /* key stored here */ 341 char *value, /* value stored here */ 342 int max_key_len, 343 int max_value_len, 344 const char **endptr) /* next search position */ 345{ 346 int c; 347 bool starts_with_quote = false; 348 bool escape = false; 349 350 for (c = max_key_len-1; (*str && (*str != '=') && c--); ) 351 *key++ = *str++; 352 *key = '\0'; 353 354 if('=' != *str++) 355 /* no key/value found */ 356 return false; 357 358 if('\"' == *str) 359 { 360 /* quoted string */ 361 str++; 362 starts_with_quote = true; 363 } 364 365 for (c = max_value_len-1; *str && c--; str++) 366 { 367 switch (*str) 368 { 369 case '\\': 370 if (!escape) 371 { 372 /* possibly the start of an escaped quote */ 373 escape = true; 374 *value++ = '\\'; /* even though this is an escape character, we still 375 store it as-is in the target buffer */ 376 continue; 377 } 378 break; 379 case ',': 380 if (!starts_with_quote) 381 { 382 /* this signals the end of the value if we didn't get a starting quote 383 and then we do "sloppy" parsing */ 384 c=0; /* the end */ 385 continue; 386 } 387 break; 388 case '\r': 389 case '\n': 390 /* end of string */ 391 c=0; 392 continue; 393 case '\"': 394 if (!escape && starts_with_quote) 395 { 396 /* end of string */ 397 c=0; 398 continue; 399 } 400 break; 401 } 402 escape = false; 403 *value++ = *str; 404 } 405 *value = '\0'; 406 407 *endptr = str; 408 409 return true; /* success */ 410} 411 412static char * 413get_pa_var (const char *key, const char *pa, struct gc_arena *gc) 414{ 415 char k[64]; 416 char v[256]; 417 const char *content = pa; 418 419 while (true) 420 { 421 const int status = get_key_value(content, k, v, sizeof(k), sizeof(v), &content); 422 if (status) 423 { 424 if (!strcmp(key, k)) 425 return string_alloc(v, gc); 426 } 427 else 428 return NULL; 429 430 /* advance to start of next key */ 431 if (*content == ',') 432 ++content; 433 while (*content && isspace(*content)) 434 ++content; 435 } 436} 437 438struct http_proxy_info * 439http_proxy_new (const struct http_proxy_options *o) 440{ 441 struct http_proxy_info *p; 442 struct http_proxy_options opt; 443 444 if (!o || !o->server) 445 msg (M_FATAL, "HTTP_PROXY: server not specified"); 446 447 ASSERT (legal_ipv4_port (o->port)); 448 449 ALLOC_OBJ_CLEAR (p, struct http_proxy_info); 450 p->options = *o; 451 452 /* parse authentication method */ 453 p->auth_method = HTTP_AUTH_NONE; 454 if (o->auth_method_string) 455 { 456 if (!strcmp (o->auth_method_string, "none")) 457 p->auth_method = HTTP_AUTH_NONE; 458 else if (!strcmp (o->auth_method_string, "basic")) 459 p->auth_method = HTTP_AUTH_BASIC; 460#if NTLM 461 else if (!strcmp (o->auth_method_string, "ntlm")) 462 p->auth_method = HTTP_AUTH_NTLM; 463 else if (!strcmp (o->auth_method_string, "ntlm2")) 464 p->auth_method = HTTP_AUTH_NTLM2; 465#endif 466 else 467 msg (M_FATAL, "ERROR: unknown HTTP authentication method: '%s'", 468 o->auth_method_string); 469 } 470 471 /* only basic and NTLM/NTLMv2 authentication supported so far */ 472 if (p->auth_method == HTTP_AUTH_BASIC || p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) 473 { 474 get_user_pass_http (p, true); 475 } 476 477#if !NTLM 478 if (p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) 479 msg (M_FATAL, "Sorry, this version of " PACKAGE_NAME " was built without NTLM Proxy support."); 480#endif 481 482 p->defined = true; 483 return p; 484} 485 486void 487http_proxy_close (struct http_proxy_info *hp) 488{ 489 free (hp); 490} 491 492bool 493establish_http_proxy_passthru (struct http_proxy_info *p, 494 socket_descriptor_t sd, /* already open to proxy */ 495 const char *host, /* openvpn server remote */ 496 const int port, /* openvpn server port */ 497 struct buffer *lookahead, 498 volatile int *signal_received) 499{ 500 struct gc_arena gc = gc_new (); 501 char buf[512]; 502 char buf2[129]; 503 char get[80]; 504 int status; 505 int nparms; 506 bool ret = false; 507 bool processed = false; 508 509 /* get user/pass if not previously given */ 510 if (p->auth_method == HTTP_AUTH_BASIC 511 || p->auth_method == HTTP_AUTH_DIGEST 512 || p->auth_method == HTTP_AUTH_NTLM) 513 get_user_pass_http (p, false); 514 515 /* are we being called again after getting the digest server nonce in the previous transaction? */ 516 if (p->auth_method == HTTP_AUTH_DIGEST && p->proxy_authenticate) 517 { 518 nparms = 1; 519 status = 407; 520 } 521 else 522 { 523 /* format HTTP CONNECT message */ 524 openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s", 525 host, 526 port, 527 p->options.http_version); 528 529 msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); 530 531 /* send HTTP CONNECT message to proxy */ 532 if (!send_line_crlf (sd, buf)) 533 goto error; 534 535 openvpn_snprintf(buf, sizeof(buf), "Host: %s", host); 536 if (!send_line_crlf(sd, buf)) 537 goto error; 538 539 /* send User-Agent string if provided */ 540 if (p->options.user_agent) 541 { 542 openvpn_snprintf (buf, sizeof(buf), "User-Agent: %s", 543 p->options.user_agent); 544 if (!send_line_crlf (sd, buf)) 545 goto error; 546 } 547 548 /* auth specified? */ 549 switch (p->auth_method) 550 { 551 case HTTP_AUTH_NONE: 552 break; 553 554 case HTTP_AUTH_BASIC: 555 openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: Basic %s", 556 username_password_as_base64 (p, &gc)); 557 msg (D_PROXY, "Attempting Basic Proxy-Authorization"); 558 dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); 559 if (!send_line_crlf (sd, buf)) 560 goto error; 561 break; 562 563#if NTLM 564 case HTTP_AUTH_NTLM: 565 case HTTP_AUTH_NTLM2: 566 /* keep-alive connection */ 567 openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive"); 568 if (!send_line_crlf (sd, buf)) 569 goto error; 570 571 openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s", 572 ntlm_phase_1 (p, &gc)); 573 msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 1"); 574 dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); 575 if (!send_line_crlf (sd, buf)) 576 goto error; 577 break; 578#endif 579 580 default: 581 ASSERT (0); 582 } 583 584 /* send empty CR, LF */ 585 if (!send_crlf (sd)) 586 goto error; 587 588 /* receive reply from proxy */ 589 if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) 590 goto error; 591 592 /* remove trailing CR, LF */ 593 chomp (buf); 594 595 msg (D_PROXY, "HTTP proxy returned: '%s'", buf); 596 597 /* parse return string */ 598 nparms = sscanf (buf, "%*s %d", &status); 599 600 } 601 602 /* check for a "407 Proxy Authentication Required" response */ 603 while (nparms >= 1 && status == 407) 604 { 605 msg (D_PROXY, "Proxy requires authentication"); 606 607 if (p->auth_method == HTTP_AUTH_BASIC && !processed) 608 { 609 processed = true; 610 } 611 else if ((p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) && !processed) /* check for NTLM */ 612 { 613#if NTLM 614 /* look for the phase 2 response */ 615 616 while (true) 617 { 618 if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) 619 goto error; 620 chomp (buf); 621 msg (D_PROXY, "HTTP proxy returned: '%s'", buf); 622 623 openvpn_snprintf (get, sizeof get, "%%*s NTLM %%%ds", (int) sizeof (buf2) - 1); 624 nparms = sscanf (buf, get, buf2); 625 buf2[128] = 0; /* we only need the beginning - ensure it's null terminated. */ 626 627 /* check for "Proxy-Authenticate: NTLM TlRM..." */ 628 if (nparms == 1) 629 { 630 /* parse buf2 */ 631 msg (D_PROXY, "auth string: '%s'", buf2); 632 break; 633 } 634 } 635 /* if we are here then auth string was got */ 636 msg (D_PROXY, "Received NTLM Proxy-Authorization phase 2 response"); 637 638 /* receive and discard everything else */ 639 while (recv_line (sd, NULL, 0, 2, true, NULL, signal_received)) 640 ; 641 642 /* now send the phase 3 reply */ 643 644 /* format HTTP CONNECT message */ 645 openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s", 646 host, 647 port, 648 p->options.http_version); 649 650 msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); 651 652 /* send HTTP CONNECT message to proxy */ 653 if (!send_line_crlf (sd, buf)) 654 goto error; 655 656 /* keep-alive connection */ 657 openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive"); 658 if (!send_line_crlf (sd, buf)) 659 goto error; 660 661 662 /* send HOST etc, */ 663 openvpn_snprintf (buf, sizeof(buf), "Host: %s", host); 664 msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); 665 if (!send_line_crlf (sd, buf)) 666 goto error; 667 668 msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 3"); 669 { 670 const char *np3 = ntlm_phase_3 (p, buf2, &gc); 671 if (!np3) 672 { 673 msg (D_PROXY, "NTLM Proxy-Authorization phase 3 failed: received corrupted data from proxy server"); 674 goto error; 675 } 676 openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s", np3); 677 } 678 679 msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); 680 if (!send_line_crlf (sd, buf)) 681 goto error; 682 /* ok so far... */ 683 /* send empty CR, LF */ 684 if (!send_crlf (sd)) 685 goto error; 686 687 /* receive reply from proxy */ 688 if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) 689 goto error; 690 691 /* remove trailing CR, LF */ 692 chomp (buf); 693 694 msg (D_PROXY, "HTTP proxy returned: '%s'", buf); 695 696 /* parse return string */ 697 nparms = sscanf (buf, "%*s %d", &status); 698 processed = true; 699#endif 700 } 701#if PROXY_DIGEST_AUTH 702 else if (p->auth_method == HTTP_AUTH_DIGEST && !processed) 703 { 704 char *pa = p->proxy_authenticate; 705 const int method = p->auth_method; 706 ASSERT(pa); 707 708 if (method == HTTP_AUTH_DIGEST) 709 { 710 const char *http_method = "CONNECT"; 711 const char *nonce_count = "00000001"; 712 const char *qop = "auth"; 713 const char *username = p->up.username; 714 const char *password = p->up.password; 715 char *opaque_kv = ""; 716 char uri[128]; 717 uint8_t cnonce_raw[8]; 718 uint8_t *cnonce; 719 HASHHEX session_key; 720 HASHHEX response; 721 722 const char *realm = get_pa_var("realm", pa, &gc); 723 const char *nonce = get_pa_var("nonce", pa, &gc); 724 const char *algor = get_pa_var("algorithm", pa, &gc); 725 const char *opaque = get_pa_var("opaque", pa, &gc); 726 727 /* generate a client nonce */ 728 ASSERT(rand_bytes(cnonce_raw, sizeof(cnonce_raw))); 729 cnonce = make_base64_string2(cnonce_raw, sizeof(cnonce_raw), &gc); 730 731 732 /* build the digest response */ 733 openvpn_snprintf (uri, sizeof(uri), "%s:%d", 734 host, 735 port); 736 737 if (opaque) 738 { 739 const int len = strlen(opaque)+16; 740 opaque_kv = gc_malloc(len, false, &gc); 741 openvpn_snprintf (opaque_kv, len, ", opaque=\"%s\"", opaque); 742 } 743 744 DigestCalcHA1(algor, 745 username, 746 realm, 747 password, 748 nonce, 749 (char *)cnonce, 750 session_key); 751 DigestCalcResponse(session_key, 752 nonce, 753 nonce_count, 754 (char *)cnonce, 755 qop, 756 http_method, 757 uri, 758 NULL, 759 response); 760 761 /* format HTTP CONNECT message */ 762 openvpn_snprintf (buf, sizeof(buf), "%s %s HTTP/%s", 763 http_method, 764 uri, 765 p->options.http_version); 766 767 msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); 768 769 /* send HTTP CONNECT message to proxy */ 770 if (!send_line_crlf (sd, buf)) 771 goto error; 772 773 /* send HOST etc, */ 774 openvpn_snprintf (buf, sizeof(buf), "Host: %s", host); 775 msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); 776 if (!send_line_crlf (sd, buf)) 777 goto error; 778 779 /* send digest response */ 780 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", 781 username, 782 realm, 783 nonce, 784 uri, 785 qop, 786 nonce_count, 787 cnonce, 788 response, 789 opaque_kv 790 ); 791 msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); 792 if (!send_line_crlf (sd, buf)) 793 goto error; 794 if (!send_crlf (sd)) 795 goto error; 796 797 /* receive reply from proxy */ 798 if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) 799 goto error; 800 801 /* remove trailing CR, LF */ 802 chomp (buf); 803 804 msg (D_PROXY, "HTTP proxy returned: '%s'", buf); 805 806 /* parse return string */ 807 nparms = sscanf (buf, "%*s %d", &status); 808 processed = true; 809 } 810 else 811 { 812 msg (D_PROXY, "HTTP proxy: digest method not supported"); 813 goto error; 814 } 815 } 816#endif 817 else if (p->options.auth_retry) 818 { 819 /* figure out what kind of authentication the proxy needs */ 820 char *pa = NULL; 821 const int method = get_proxy_authenticate(sd, 822 p->options.timeout, 823 &pa, 824 NULL, 825 signal_received); 826 if (method != HTTP_AUTH_NONE) 827 { 828 if (pa) 829 msg (D_PROXY, "HTTP proxy authenticate '%s'", pa); 830 if (p->options.auth_retry == PAR_NCT && method == HTTP_AUTH_BASIC) 831 { 832 msg (D_PROXY, "HTTP proxy: support for basic auth and other cleartext proxy auth methods is disabled"); 833 goto error; 834 } 835 p->auth_method = method; 836 store_proxy_authenticate(p, pa); 837 ret = true; 838 goto done; 839 } 840 else 841 { 842 msg (D_PROXY, "HTTP proxy: do not recognize the authentication method required by proxy"); 843 free (pa); 844 goto error; 845 } 846 } 847 else 848 { 849 if (!processed) 850 msg (D_PROXY, "HTTP proxy: no support for proxy authentication method"); 851 goto error; 852 } 853 854 /* clear state */ 855 if (p->options.auth_retry) 856 clear_user_pass_http(); 857 store_proxy_authenticate(p, NULL); 858 } 859 860 /* check return code, success = 200 */ 861 if (nparms < 1 || status != 200) 862 { 863 msg (D_LINK_ERRORS, "HTTP proxy returned bad status"); 864#if 0 865 /* DEBUGGING -- show a multi-line HTTP error response */ 866 dump_residual(sd, p->options.timeout, signal_received); 867#endif 868 goto error; 869 } 870 871 /* SUCCESS */ 872 873 /* receive line from proxy and discard */ 874 if (!recv_line (sd, NULL, 0, p->options.timeout, true, NULL, signal_received)) 875 goto error; 876 877 /* 878 * Toss out any extraneous chars, but don't throw away the 879 * start of the OpenVPN data stream (put it in lookahead). 880 */ 881 while (recv_line (sd, NULL, 0, 2, false, lookahead, signal_received)) 882 ; 883 884 /* reset queried_creds so that we don't think that the next creds request is due to an auth error */ 885 p->queried_creds = false; 886 887#if 0 888 if (lookahead && BLEN (lookahead)) 889 msg (M_INFO, "HTTP PROXY: lookahead: %s", format_hex (BPTR (lookahead), BLEN (lookahead), 0)); 890#endif 891 892 done: 893 gc_free (&gc); 894 return ret; 895 896 error: 897 /* on error, should we exit or restart? */ 898 if (!*signal_received) 899 *signal_received = (p->options.retry ? SIGUSR1 : SIGTERM); /* SOFT-SIGUSR1 -- HTTP proxy error */ 900 gc_free (&gc); 901 return ret; 902} 903 904#else 905static void dummy(void) {} 906#endif /* ENABLE_HTTP_PROXY */ 907 908