221
225
if (!static_proxy_user_pass.defined || force)
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,
226
GET_USER_PASS_MANAGEMENT);
234
p->queried_creds = true;
227
235
p->up = static_proxy_user_pass;
239
clear_user_pass_http (void)
241
purge_user_pass (&static_proxy_user_pass, true);
245
dump_residual (socket_descriptor_t sd,
247
volatile int *signal_received)
252
if (!recv_line (sd, buf, sizeof (buf), timeout, true, NULL, signal_received))
255
msg (D_PROXY, "PROXY HEADER: '%s'", buf);
260
* Extract the Proxy-Authenticate header from the stream.
261
* Consumes all headers.
264
get_proxy_authenticate (socket_descriptor_t sd,
268
volatile int *signal_received)
271
int ret = HTTP_AUTH_NONE;
274
if (!recv_line (sd, buf, sizeof (buf), timeout, true, NULL, signal_received))
277
return HTTP_AUTH_NONE;
282
if (ret == HTTP_AUTH_NONE && !strncmp(buf, "Proxy-Authenticate: ", 20))
284
if (!strncmp(buf+20, "Basic ", 6))
286
msg (D_PROXY, "PROXY AUTH BASIC: '%s'", buf);
287
*data = string_alloc(buf+26, gc);
288
ret = HTTP_AUTH_BASIC;
290
#if PROXY_DIGEST_AUTH
291
else if (!strncmp(buf+20, "Digest ", 7))
293
msg (D_PROXY, "PROXY AUTH DIGEST: '%s'", buf);
294
*data = string_alloc(buf+27, gc);
295
ret = HTTP_AUTH_DIGEST;
299
else if (!strncmp(buf+20, "NTLM", 4))
301
msg (D_PROXY, "PROXY AUTH HTLM: '%s'", buf);
303
ret = HTTP_AUTH_NTLM;
311
store_proxy_authenticate (struct http_proxy_info *p, char *data)
313
if (p->proxy_authenticate)
314
free (p->proxy_authenticate);
315
p->proxy_authenticate = data;
319
* Parse out key/value pairs from Proxy-Authenticate string.
320
* Return true on success, or false on parse failure.
323
get_key_value(const char *str, /* source string */
324
char *key, /* key stored here */
325
char *value, /* value stored here */
328
const char **endptr) /* next search position */
331
bool starts_with_quote = false;
334
for (c = max_key_len-1; (*str && (*str != '=') && c--); )
339
/* no key/value found */
346
starts_with_quote = true;
349
for (c = max_value_len-1; *str && c--; str++)
356
/* possibly the start of an escaped quote */
358
*value++ = '\\'; /* even though this is an escape character, we still
359
store it as-is in the target buffer */
364
if (!starts_with_quote)
366
/* this signals the end of the value if we didn't get a starting quote
367
and then we do "sloppy" parsing */
378
if (!escape && starts_with_quote)
393
return true; /* success */
397
get_pa_var (const char *key, const char *pa, struct gc_arena *gc)
401
const char *content = pa;
405
const int status = get_key_value(content, k, v, sizeof(k), sizeof(v), &content);
409
return string_alloc(v, gc);
414
/* advance to start of next key */
417
while (*content && isspace(*content))
231
422
struct http_proxy_info *
232
423
http_proxy_new (const struct http_proxy_options *o,
324
518
volatile int *signal_received)
326
520
struct gc_arena gc = gc_new ();
332
526
bool ret = false;
527
bool processed = false;
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);
339
/* format HTTP CONNECT message */
340
openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s",
343
p->options.http_version);
345
msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
347
/* send HTTP CONNECT message to proxy */
348
if (!send_line_crlf (sd, buf))
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)
354
openvpn_snprintf (buf, sizeof(buf), "User-Agent: %s",
355
p->options.user_agent);
356
if (!send_line_crlf (sd, buf))
360
/* auth specified? */
361
switch (p->auth_method)
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);
543
/* format HTTP CONNECT message */
544
openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s",
547
p->options.http_version);
549
msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
551
/* send HTTP CONNECT message to proxy */
372
552
if (!send_line_crlf (sd, buf))
555
/* send User-Agent string if provided */
556
if (p->options.user_agent)
558
openvpn_snprintf (buf, sizeof(buf), "User-Agent: %s",
559
p->options.user_agent);
560
if (!send_line_crlf (sd, buf))
564
/* auth specified? */
565
switch (p->auth_method)
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))
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))
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))
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);
389
if (!send_line_crlf (sd, buf))
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))
600
/* send empty CR, LF */
604
/* receive reply from proxy */
605
if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received))
608
/* remove trailing CR, LF */
611
msg (D_PROXY, "HTTP proxy returned: '%s'", buf);
613
/* parse return string */
614
nparms = sscanf (buf, "%*s %d", &status);
398
/* send empty CR, LF */
403
/* receive reply from proxy */
404
if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received))
407
/* remove trailing CR, LF */
410
msg (D_PROXY, "HTTP proxy returned: '%s'", buf);
412
/* parse return string */
413
nparms = sscanf (buf, "%*s %d", &status);
415
618
/* check for a "407 Proxy Authentication Required" response */
416
if (nparms >= 1 && status == 407)
619
while (nparms >= 1 && status == 407)
418
621
msg (D_PROXY, "Proxy requires authentication");
421
if (p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2)
623
if (p->auth_method == HTTP_AUTH_BASIC && !processed)
627
else if ((p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) && !processed) /* check for NTLM */
424
630
/* look for the phase 2 response */
509
712
/* parse return string */
510
713
nparms = sscanf (buf, "%*s %d", &status);
512
ASSERT (0); /* No NTLM support */
515
else if (p->auth_method == HTTP_AUTH_NONE && p->options.auth_retry)
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.
524
p->auth_method = HTTP_AUTH_BASIC;
717
#if PROXY_DIGEST_AUTH
718
else if (p->auth_method == HTTP_AUTH_DIGEST && !processed)
720
char *pa = p->proxy_authenticate;
721
const int method = p->auth_method;
724
if (method == HTTP_AUTH_DIGEST)
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 = "";
733
uint8_t cnonce_raw[8];
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);
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);
748
/* build the digest response */
749
openvpn_snprintf (uri, sizeof(uri), "%s:%d",
755
const int len = strlen(opaque)+16;
756
opaque_kv = gc_malloc(len, false, &gc);
757
openvpn_snprintf (opaque_kv, len, ", opaque=\"%s\"", opaque);
767
DigestCalcResponse(session_key,
777
/* format HTTP CONNECT message */
778
openvpn_snprintf (buf, sizeof(buf), "%s %s HTTP/%s",
781
p->options.http_version);
783
msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
785
/* send HTTP CONNECT message to proxy */
786
if (!send_line_crlf (sd, buf))
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))
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",
807
msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
808
if (!send_line_crlf (sd, buf))
813
/* receive reply from proxy */
814
if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received))
817
/* remove trailing CR, LF */
820
msg (D_PROXY, "HTTP proxy returned: '%s'", buf);
822
/* parse return string */
823
nparms = sscanf (buf, "%*s %d", &status);
828
msg (D_PROXY, "HTTP proxy: digest method not supported");
833
else if (p->options.auth_retry)
835
/* figure out what kind of authentication the proxy needs */
837
const int method = get_proxy_authenticate(sd,
842
if (method != HTTP_AUTH_NONE)
845
msg (D_PROXY, "HTTP proxy authenticate '%s'", pa);
846
if (p->options.auth_retry == PAR_NCT && method == HTTP_AUTH_BASIC)
848
msg (D_PROXY, "HTTP proxy: support for basic auth and other cleartext proxy auth methods is disabled");
851
p->auth_method = method;
852
store_proxy_authenticate(p, pa);
858
msg (D_PROXY, "HTTP proxy: do not recognize the authentication method required by proxy");
866
msg (D_PROXY, "HTTP proxy: no support for proxy authentication method");
871
if (p->options.auth_retry)
872
clear_user_pass_http();
873
store_proxy_authenticate(p, NULL);
533
876
/* check return code, success = 200 */
534
877
if (nparms < 1 || status != 200)
536
879
msg (D_LINK_ERRORS, "HTTP proxy returned bad status");
538
881
/* DEBUGGING -- show a multi-line HTTP error response */
541
if (!recv_line (sd, buf, sizeof (buf), p->options.timeout, true, NULL, signal_received))
544
msg (D_PROXY, "HTTP proxy returned: '%s'", buf);
882
dump_residual(sd, p->options.timeout, signal_received);
550
889
/* receive line from proxy and discard */
551
890
if (!recv_line (sd, NULL, 0, p->options.timeout, true, NULL, signal_received))