~ubuntu-branches/ubuntu/precise/openvpn/precise-updates

« back to all changes in this revision

Viewing changes to proxy.c

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short
  • Date: 2010-10-05 06:21:14 UTC
  • mfrom: (1.1.16 upstream) (10.2.8 sid)
  • Revision ID: james.westby@ubuntu.com-20101005062114-18lyqud9e3p4g735
Tags: 2.1.3-1ubuntu1
* Merge from debian unstable.  Remaining changes:
  + debian/openvpn.init.d:
    - Do not use start-stop-daemon and </dev/null to avoid blocking boot.
    - Show per-VPN result messages.
    - Add "--script-security 2" by default for backwards compatablitiy
  + debian/control: Add lsb-base >= 3.2-14 to allow status_of_proc()

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
 *             packet encryption, packet authentication, and
6
6
 *             packet compression.
7
7
 *
8
 
 *  Copyright (C) 2002-2009 OpenVPN Technologies, Inc. <sales@openvpn.net>
 
8
 *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
9
9
 *
10
10
 *  This program is free software; you can redistribute it and/or modify
11
11
 *  it under the terms of the GNU General Public License version 2
26
26
 
27
27
#include "common.h"
28
28
#include "misc.h"
 
29
#include "crypto.h"
29
30
#include "win32.h"
30
31
#include "socket.h"
31
32
#include "fdmisc.h"
32
33
#include "proxy.h"
33
34
#include "base64.h"
 
35
#include "httpdigest.h"
34
36
#include "ntlm.h"
35
37
 
36
38
#ifdef WIN32
41
43
 
42
44
#ifdef ENABLE_HTTP_PROXY
43
45
 
 
46
#define UP_TYPE_PROXY        "HTTP Proxy"
 
47
 
44
48
/* cached proxy username/password */
45
49
static struct user_pass static_proxy_user_pass;
46
50
 
220
224
{
221
225
  if (!static_proxy_user_pass.defined || force)
222
226
    {
 
227
      unsigned int flags = GET_USER_PASS_MANAGEMENT;
 
228
      if (p->queried_creds)
 
229
        flags |= GET_USER_PASS_PREVIOUS_CREDS_FAILED;
223
230
      get_user_pass (&static_proxy_user_pass,
224
231
                     p->options.auth_file,
225
 
                     "HTTP Proxy",
226
 
                     GET_USER_PASS_MANAGEMENT);
 
232
                     UP_TYPE_PROXY,
 
233
                     flags);
 
234
      p->queried_creds = true;
227
235
      p->up = static_proxy_user_pass;
228
236
    }
229
237
}
 
238
static void
 
239
clear_user_pass_http (void)
 
240
{
 
241
  purge_user_pass (&static_proxy_user_pass, true);
 
242
}
 
243
 
 
244
static void
 
245
dump_residual (socket_descriptor_t sd,
 
246
               int timeout,
 
247
               volatile int *signal_received)
 
248
{
 
249
  char buf[256];
 
250
  while (true)
 
251
    {
 
252
      if (!recv_line (sd, buf, sizeof (buf), timeout, true, NULL, signal_received))
 
253
        return;
 
254
      chomp (buf);
 
255
      msg (D_PROXY, "PROXY HEADER: '%s'", buf);
 
256
    }
 
257
}
 
258
 
 
259
/*
 
260
 * Extract the Proxy-Authenticate header from the stream.
 
261
 * Consumes all headers.
 
262
 */
 
263
static int
 
264
get_proxy_authenticate (socket_descriptor_t sd,
 
265
                        int timeout,
 
266
                        char **data,
 
267
                        struct gc_arena *gc,
 
268
                        volatile int *signal_received)
 
269
{
 
270
  char buf[256];
 
271
  int ret = HTTP_AUTH_NONE;
 
272
  while (true)
 
273
    {
 
274
      if (!recv_line (sd, buf, sizeof (buf), timeout, true, NULL, signal_received))
 
275
        {
 
276
          *data = NULL;
 
277
          return HTTP_AUTH_NONE;
 
278
        }
 
279
      chomp (buf);
 
280
      if (!strlen(buf))
 
281
        return ret;
 
282
      if (ret == HTTP_AUTH_NONE && !strncmp(buf, "Proxy-Authenticate: ", 20))
 
283
        {
 
284
          if (!strncmp(buf+20, "Basic ", 6))
 
285
            {
 
286
              msg (D_PROXY, "PROXY AUTH BASIC: '%s'", buf);
 
287
              *data = string_alloc(buf+26, gc);
 
288
              ret = HTTP_AUTH_BASIC;
 
289
            }
 
290
#if PROXY_DIGEST_AUTH
 
291
          else if (!strncmp(buf+20, "Digest ", 7))
 
292
            {
 
293
              msg (D_PROXY, "PROXY AUTH DIGEST: '%s'", buf);
 
294
              *data = string_alloc(buf+27, gc);
 
295
              ret = HTTP_AUTH_DIGEST;
 
296
            }
 
297
#endif
 
298
#if NTLM
 
299
          else if (!strncmp(buf+20, "NTLM", 4))
 
300
            {
 
301
              msg (D_PROXY, "PROXY AUTH HTLM: '%s'", buf);
 
302
              *data = NULL;
 
303
              ret = HTTP_AUTH_NTLM;
 
304
            }
 
305
#endif
 
306
        }
 
307
    }
 
308
}
 
309
 
 
310
static void
 
311
store_proxy_authenticate (struct http_proxy_info *p, char *data)
 
312
{
 
313
  if (p->proxy_authenticate)
 
314
    free (p->proxy_authenticate);
 
315
  p->proxy_authenticate = data;
 
316
}
 
317
 
 
318
/*
 
319
 * Parse out key/value pairs from Proxy-Authenticate string.
 
320
 * Return true on success, or false on parse failure.
 
321
 */
 
322
static bool
 
323
get_key_value(const char *str,       /* source string */
 
324
              char *key,             /* key stored here */
 
325
              char *value,           /* value stored here */
 
326
              int max_key_len,
 
327
              int max_value_len,
 
328
              const char **endptr)   /* next search position */
 
329
{
 
330
  int c;
 
331
  bool starts_with_quote = false;
 
332
  bool escape = false;
 
333
 
 
334
  for (c = max_key_len-1; (*str && (*str != '=') && c--); )
 
335
    *key++ = *str++;
 
336
  *key = '\0';
 
337
 
 
338
  if('=' != *str++)
 
339
    /* no key/value found */
 
340
    return false;
 
341
 
 
342
  if('\"' == *str)
 
343
    {
 
344
      /* quoted string */
 
345
      str++;
 
346
      starts_with_quote = true;
 
347
    }
 
348
 
 
349
  for (c = max_value_len-1; *str && c--; str++)
 
350
    {
 
351
      switch (*str)
 
352
        {
 
353
        case '\\':
 
354
          if (!escape)
 
355
            {
 
356
              /* possibly the start of an escaped quote */
 
357
              escape = true;
 
358
              *value++ = '\\'; /* even though this is an escape character, we still
 
359
                                  store it as-is in the target buffer */
 
360
              continue;
 
361
            }
 
362
          break;
 
363
        case ',':
 
364
          if (!starts_with_quote)
 
365
            {
 
366
              /* this signals the end of the value if we didn't get a starting quote
 
367
                 and then we do "sloppy" parsing */
 
368
              c=0; /* the end */
 
369
              continue;
 
370
            }
 
371
          break;
 
372
        case '\r':
 
373
        case '\n':
 
374
          /* end of string */
 
375
          c=0;
 
376
        continue;
 
377
        case '\"':
 
378
          if (!escape && starts_with_quote)
 
379
            {
 
380
              /* end of string */
 
381
              c=0;
 
382
              continue;
 
383
            }
 
384
          break;
 
385
        }
 
386
      escape = false;
 
387
      *value++ = *str;
 
388
    }
 
389
  *value = '\0';
 
390
 
 
391
  *endptr = str;
 
392
 
 
393
  return true; /* success */
 
394
}
 
395
 
 
396
static char *
 
397
get_pa_var (const char *key, const char *pa, struct gc_arena *gc)
 
398
{
 
399
  char k[64];
 
400
  char v[256];
 
401
  const char *content = pa;
 
402
 
 
403
  while (true)
 
404
    {
 
405
      const int status = get_key_value(content, k, v, sizeof(k), sizeof(v), &content);
 
406
      if (status)
 
407
        {
 
408
          if (!strcmp(key, k))
 
409
            return string_alloc(v, gc);
 
410
        }
 
411
      else
 
412
        return NULL;
 
413
 
 
414
      /* advance to start of next key */
 
415
      if (*content == ',')
 
416
        ++content;
 
417
      while (*content && isspace(*content))
 
418
        ++content;
 
419
    }
 
420
}
230
421
 
231
422
struct http_proxy_info *
232
423
http_proxy_new (const struct http_proxy_options *o,
263
454
 
264
455
          opt.server = auto_proxy_info->http.server;
265
456
          opt.port = auto_proxy_info->http.port;
266
 
          opt.auth_retry = true;
 
457
          if (!opt.auth_retry)
 
458
            opt.auth_retry = PAR_ALL;
267
459
 
268
460
          o = &opt;
269
461
        }
285
477
        p->auth_method = HTTP_AUTH_NONE;
286
478
      else if (!strcmp (o->auth_method_string, "basic"))
287
479
        p->auth_method = HTTP_AUTH_BASIC;
 
480
#if NTLM
288
481
      else if (!strcmp (o->auth_method_string, "ntlm"))
289
482
        p->auth_method = HTTP_AUTH_NTLM;
290
483
      else if (!strcmp (o->auth_method_string, "ntlm2"))
291
484
        p->auth_method = HTTP_AUTH_NTLM2;
 
485
#endif
292
486
      else
293
 
        msg (M_FATAL, "ERROR: unknown HTTP authentication method: '%s' -- only the 'none', 'basic', 'ntlm', or 'ntlm2' methods are currently supported",
 
487
        msg (M_FATAL, "ERROR: unknown HTTP authentication method: '%s'",
294
488
             o->auth_method_string);
295
489
    }
296
490
 
324
518
                               volatile int *signal_received)
325
519
{
326
520
  struct gc_arena gc = gc_new ();
327
 
  char buf[256];
 
521
  char buf[512];
328
522
  char buf2[128];
329
523
  char get[80];
330
524
  int status;
331
525
  int nparms;
332
526
  bool ret = false;
 
527
  bool processed = false;
333
528
 
334
529
  /* get user/pass if not previously given or if --auto-proxy is being used */
335
530
  if (p->auth_method == HTTP_AUTH_BASIC
 
531
      || p->auth_method == HTTP_AUTH_DIGEST
336
532
      || p->auth_method == HTTP_AUTH_NTLM)
337
533
    get_user_pass_http (p, false);
338
534
 
339
 
  /* format HTTP CONNECT message */
340
 
  openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s",
341
 
                    host,
342
 
                    port,
343
 
                    p->options.http_version);
344
 
 
345
 
  msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
346
 
 
347
 
  /* send HTTP CONNECT message to proxy */
348
 
  if (!send_line_crlf (sd, buf))
349
 
    goto error;
350
 
 
351
 
  /* send User-Agent string if provided */
352
 
  if (p->options.user_agent)
 
535
  /* are we being called again after getting the digest server nonce in the previous transaction? */
 
536
  if (p->auth_method == HTTP_AUTH_DIGEST && p->proxy_authenticate)
353
537
    {
354
 
      openvpn_snprintf (buf, sizeof(buf), "User-Agent: %s",
355
 
                        p->options.user_agent);
356
 
      if (!send_line_crlf (sd, buf))
357
 
        goto error;
 
538
      nparms = 1;
 
539
      status = 407;
358
540
    }
359
 
 
360
 
  /* auth specified? */
361
 
  switch (p->auth_method)
 
541
  else
362
542
    {
363
 
    case HTTP_AUTH_NONE:
364
 
      break;
365
 
 
366
 
    case HTTP_AUTH_BASIC:
367
 
      openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: Basic %s",
368
 
                        username_password_as_base64 (p, &gc));
369
 
      msg (D_PROXY, "Attempting Basic Proxy-Authorization");
370
 
      dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf);
371
 
      openvpn_sleep (1);
 
543
      /* format HTTP CONNECT message */
 
544
      openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s",
 
545
                        host,
 
546
                        port,
 
547
                        p->options.http_version);
 
548
 
 
549
      msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
 
550
 
 
551
      /* send HTTP CONNECT message to proxy */
372
552
      if (!send_line_crlf (sd, buf))
373
553
        goto error;
374
 
      break;
 
554
 
 
555
      /* send User-Agent string if provided */
 
556
      if (p->options.user_agent)
 
557
        {
 
558
          openvpn_snprintf (buf, sizeof(buf), "User-Agent: %s",
 
559
                            p->options.user_agent);
 
560
          if (!send_line_crlf (sd, buf))
 
561
            goto error;
 
562
        }
 
563
 
 
564
      /* auth specified? */
 
565
      switch (p->auth_method)
 
566
        {
 
567
        case HTTP_AUTH_NONE:
 
568
          break;
 
569
 
 
570
        case HTTP_AUTH_BASIC:
 
571
          openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: Basic %s",
 
572
                            username_password_as_base64 (p, &gc));
 
573
          msg (D_PROXY, "Attempting Basic Proxy-Authorization");
 
574
          dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf);
 
575
          if (!send_line_crlf (sd, buf))
 
576
            goto error;
 
577
          break;
375
578
 
376
579
#if NTLM
377
 
    case HTTP_AUTH_NTLM:
378
 
    case HTTP_AUTH_NTLM2:
379
 
      /* keep-alive connection */
380
 
      openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive");
381
 
      if (!send_line_crlf (sd, buf))
382
 
        goto error;
 
580
        case HTTP_AUTH_NTLM:
 
581
        case HTTP_AUTH_NTLM2:
 
582
          /* keep-alive connection */
 
583
          openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive");
 
584
          if (!send_line_crlf (sd, buf))
 
585
            goto error;
383
586
 
384
 
      openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s",
385
 
                        ntlm_phase_1 (p, &gc));
386
 
      msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 1");
387
 
      dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf);
388
 
      openvpn_sleep (1);
389
 
      if (!send_line_crlf (sd, buf))
390
 
        goto error;
391
 
      break;
 
587
          openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s",
 
588
                            ntlm_phase_1 (p, &gc));
 
589
          msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 1");
 
590
          dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf);
 
591
          if (!send_line_crlf (sd, buf))
 
592
            goto error;
 
593
          break;
392
594
#endif
393
595
 
394
 
    default:
395
 
      ASSERT (0);
 
596
        default:
 
597
          ASSERT (0);
 
598
        }
 
599
 
 
600
      /* send empty CR, LF */
 
601
      if (!send_crlf (sd))
 
602
        goto error;
 
603
 
 
604
      /* receive reply from proxy */
 
605
      if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received))
 
606
        goto error;
 
607
 
 
608
      /* remove trailing CR, LF */
 
609
      chomp (buf);
 
610
 
 
611
      msg (D_PROXY, "HTTP proxy returned: '%s'", buf);
 
612
 
 
613
      /* parse return string */
 
614
      nparms = sscanf (buf, "%*s %d", &status);
 
615
 
396
616
    }
397
617
 
398
 
  /* send empty CR, LF */
399
 
  openvpn_sleep (1);
400
 
  if (!send_crlf (sd))
401
 
    goto error;
402
 
 
403
 
  /* receive reply from proxy */
404
 
  if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received))
405
 
    goto error;
406
 
 
407
 
  /* remove trailing CR, LF */
408
 
  chomp (buf);
409
 
 
410
 
  msg (D_PROXY, "HTTP proxy returned: '%s'", buf);
411
 
 
412
 
  /* parse return string */
413
 
  nparms = sscanf (buf, "%*s %d", &status);
414
 
 
415
618
  /* check for a "407 Proxy Authentication Required" response */
416
 
  if (nparms >= 1 && status == 407)
 
619
  while (nparms >= 1 && status == 407)
417
620
    {
418
621
      msg (D_PROXY, "Proxy requires authentication");
419
622
 
420
 
      /* check for NTLM */
421
 
      if (p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2)
 
623
      if (p->auth_method == HTTP_AUTH_BASIC && !processed)
 
624
        {
 
625
          processed = true;
 
626
        }
 
627
      else if ((p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) && !processed) /* check for NTLM */
422
628
        {
423
629
#if NTLM
424
630
          /* look for the phase 2 response */
446
652
          msg (D_PROXY, "Received NTLM Proxy-Authorization phase 2 response");
447
653
 
448
654
          /* receive and discard everything else */
449
 
          while (recv_line (sd, NULL, 0, p->options.timeout, true, NULL, signal_received))
 
655
          while (recv_line (sd, NULL, 0, 2, true, NULL, signal_received))
450
656
            ;
451
657
 
452
658
          /* now send the phase 3 reply */
470
676
 
471
677
          
472
678
          /* send HOST etc, */
473
 
          openvpn_sleep (1);
474
679
          openvpn_snprintf (buf, sizeof(buf), "Host: %s", host);
475
680
          msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
476
681
          if (!send_line_crlf (sd, buf))
488
693
          }
489
694
 
490
695
          msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
491
 
          openvpn_sleep (1);
492
696
          if (!send_line_crlf (sd, buf))
493
697
            goto error;
494
698
          /* ok so far... */
495
699
          /* send empty CR, LF */
496
 
          openvpn_sleep (1);
497
700
          if (!send_crlf (sd))
498
701
            goto error;
499
702
 
508
711
 
509
712
          /* parse return string */
510
713
          nparms = sscanf (buf, "%*s %d", &status);
511
 
#else
512
 
          ASSERT (0); /* No NTLM support */
513
 
#endif
514
 
        }
515
 
      else if (p->auth_method == HTTP_AUTH_NONE && p->options.auth_retry)
516
 
        {
517
 
          /*
518
 
           * Proxy needs authentication, but we don't have a user/pass.
519
 
           * Now we will change p->auth_method and return true so that
520
 
           * our caller knows to call us again on a newly opened socket.
521
 
           * JYFIXME: This code needs to check proxy error output and set
522
 
           * JYFIXME: p->auth_method = HTTP_AUTH_NTLM if necessary.
523
 
           */
524
 
          p->auth_method = HTTP_AUTH_BASIC;
525
 
          ret = true;
526
 
          goto done;
 
714
          processed = true;
 
715
#endif
 
716
        }
 
717
#if PROXY_DIGEST_AUTH
 
718
      else if (p->auth_method == HTTP_AUTH_DIGEST && !processed)
 
719
        {
 
720
          char *pa = p->proxy_authenticate;
 
721
          const int method = p->auth_method;
 
722
          ASSERT(pa);
 
723
 
 
724
          if (method == HTTP_AUTH_DIGEST)
 
725
            {
 
726
              const char *http_method = "CONNECT";
 
727
              const char *nonce_count = "00000001";
 
728
              const char *qop = "auth";
 
729
              const char *username = p->up.username;
 
730
              const char *password = p->up.password;
 
731
              char *opaque_kv = "";
 
732
              char uri[128];
 
733
              uint8_t cnonce_raw[8];
 
734
              uint8_t *cnonce;
 
735
              HASHHEX session_key;
 
736
              HASHHEX response;
 
737
 
 
738
              const char *realm = get_pa_var("realm", pa, &gc);
 
739
              const char *nonce = get_pa_var("nonce", pa, &gc);
 
740
              const char *algor = get_pa_var("algorithm", pa, &gc);
 
741
              const char *opaque = get_pa_var("opaque", pa, &gc);
 
742
 
 
743
              /* generate a client nonce */
 
744
              ASSERT(RAND_bytes(cnonce_raw, sizeof(cnonce_raw)));
 
745
              cnonce = make_base64_string2(cnonce_raw, sizeof(cnonce_raw), &gc);
 
746
 
 
747
 
 
748
              /* build the digest response */
 
749
              openvpn_snprintf (uri, sizeof(uri), "%s:%d",
 
750
                                host,
 
751
                                port);
 
752
 
 
753
              if (opaque)
 
754
                {
 
755
                  const int len = strlen(opaque)+16;
 
756
                  opaque_kv = gc_malloc(len, false, &gc);
 
757
                  openvpn_snprintf (opaque_kv, len, ", opaque=\"%s\"", opaque);
 
758
                }
 
759
 
 
760
              DigestCalcHA1(algor,
 
761
                            username,
 
762
                            realm,
 
763
                            password,
 
764
                            nonce,
 
765
                            (char *)cnonce,
 
766
                            session_key);
 
767
              DigestCalcResponse(session_key,
 
768
                                 nonce,
 
769
                                 nonce_count,
 
770
                                 (char *)cnonce,
 
771
                                 qop,
 
772
                                 http_method,
 
773
                                 uri,
 
774
                                 NULL,
 
775
                                 response);
 
776
 
 
777
              /* format HTTP CONNECT message */
 
778
              openvpn_snprintf (buf, sizeof(buf), "%s %s HTTP/%s",
 
779
                                http_method,
 
780
                                uri,
 
781
                                p->options.http_version);
 
782
 
 
783
              msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
 
784
 
 
785
              /* send HTTP CONNECT message to proxy */
 
786
              if (!send_line_crlf (sd, buf))
 
787
                goto error;
 
788
 
 
789
              /* send HOST etc, */
 
790
              openvpn_snprintf (buf, sizeof(buf), "Host: %s", host);
 
791
              msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
 
792
              if (!send_line_crlf (sd, buf))
 
793
                goto error;
 
794
 
 
795
              /* send digest response */
 
796
              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",
 
797
                                username,
 
798
                                realm,
 
799
                                nonce,
 
800
                                uri,
 
801
                                qop,
 
802
                                nonce_count,
 
803
                                cnonce,
 
804
                                response,
 
805
                                opaque_kv
 
806
                                );
 
807
              msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
 
808
              if (!send_line_crlf (sd, buf))
 
809
                goto error;
 
810
              if (!send_crlf (sd))
 
811
                goto error;
 
812
 
 
813
              /* receive reply from proxy */
 
814
              if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received))
 
815
                goto error;
 
816
 
 
817
              /* remove trailing CR, LF */
 
818
              chomp (buf);
 
819
 
 
820
              msg (D_PROXY, "HTTP proxy returned: '%s'", buf);
 
821
 
 
822
              /* parse return string */
 
823
              nparms = sscanf (buf, "%*s %d", &status);
 
824
              processed = true;
 
825
            }
 
826
          else
 
827
            {
 
828
              msg (D_PROXY, "HTTP proxy: digest method not supported");
 
829
              goto error;
 
830
            }
 
831
        }
 
832
#endif
 
833
      else if (p->options.auth_retry)
 
834
        {
 
835
          /* figure out what kind of authentication the proxy needs */
 
836
          char *pa = NULL;
 
837
          const int method = get_proxy_authenticate(sd,
 
838
                                                    p->options.timeout,
 
839
                                                    &pa,
 
840
                                                    NULL,
 
841
                                                    signal_received);
 
842
          if (method != HTTP_AUTH_NONE)
 
843
            {
 
844
              if (pa)
 
845
                msg (D_PROXY, "HTTP proxy authenticate '%s'", pa);
 
846
              if (p->options.auth_retry == PAR_NCT && method == HTTP_AUTH_BASIC)
 
847
                {
 
848
                  msg (D_PROXY, "HTTP proxy: support for basic auth and other cleartext proxy auth methods is disabled");
 
849
                  goto error;
 
850
                }
 
851
              p->auth_method = method;
 
852
              store_proxy_authenticate(p, pa);
 
853
              ret = true;
 
854
              goto done;
 
855
            }
 
856
          else
 
857
            {
 
858
              msg (D_PROXY, "HTTP proxy: do not recognize the authentication method required by proxy");
 
859
              free (pa);
 
860
              goto error;
 
861
            }
527
862
        }
528
863
      else
529
 
        goto error;
 
864
        {
 
865
          if (!processed)
 
866
            msg (D_PROXY, "HTTP proxy: no support for proxy authentication method");
 
867
          goto error;
 
868
        }
 
869
 
 
870
      /* clear state */
 
871
      if (p->options.auth_retry)
 
872
        clear_user_pass_http();
 
873
      store_proxy_authenticate(p, NULL);
530
874
    }
531
875
 
532
 
 
533
876
  /* check return code, success = 200 */
534
877
  if (nparms < 1 || status != 200)
535
878
    {
536
879
      msg (D_LINK_ERRORS, "HTTP proxy returned bad status");
537
880
#if 0
538
881
      /* DEBUGGING -- show a multi-line HTTP error response */
539
 
      while (true)
540
 
        {
541
 
          if (!recv_line (sd, buf, sizeof (buf), p->options.timeout, true, NULL, signal_received))
542
 
            goto error;
543
 
          chomp (buf);
544
 
          msg (D_PROXY, "HTTP proxy returned: '%s'", buf);
545
 
        }
 
882
      dump_residual(sd, p->options.timeout, signal_received);
546
883
#endif
547
884
      goto error;
548
885
    }
549
886
 
 
887
  /* SUCCESS */
 
888
 
550
889
  /* receive line from proxy and discard */
551
890
  if (!recv_line (sd, NULL, 0, p->options.timeout, true, NULL, signal_received))
552
891
    goto error;
558
897
  while (recv_line (sd, NULL, 0, 2, false, lookahead, signal_received))
559
898
    ;
560
899
 
 
900
  /* reset queried_creds so that we don't think that the next creds request is due to an auth error */
 
901
  p->queried_creds = false;
 
902
 
561
903
#if 0
562
904
  if (lookahead && BLEN (lookahead))
563
905
    msg (M_INFO, "HTTP PROXY: lookahead: %s", format_hex (BPTR (lookahead), BLEN (lookahead), 0));