CVE-2026-86414: leaking host credentials to HTTP proxy
What the report claims
A malicious HTTP proxy can trick libcurl into sending origin credentials (Basic password or Kerberos ticket) to itself by responding to a CONNECT tunnel request with 401 WWW-Authenticate instead of 407 Proxy-Authenticate, causing the credentials to be stored in the origin's auth state and leaked over the tunnel.
Compare with curl's recorded outcome
Known vulnerability
A real vulnerability: CVE-2026-86414 leaking host credentials to HTTP proxy
Shown for comparison after analysis. The pipeline did not see this label.
ProveIt's finding
The code supports the reported flaw. A maintainer should review its impact and decide what to do next.
Why this finding?
- The CONNECT tunnel response handlers in both http_proxy.c (H2/H3) and cf-h1-proxy.c (H1) use only the status code (401 vs 407) to decide whether an auth header applies to the proxy or the origin, with no check for whether the tunnel is still being negotiated.
- When a 401 WWW-Authenticate is received during CONNECT, Curl_http_input_auth is called with proxy=false, causing it to update data->state.authhost (origin auth state) instead of data->state.authproxy.
- On CONNECT retry, output_auth_headers with proxy=false emits 'Authorization: Basic' (not 'Proxy-Authorization') using data->state.creds (origin credentials), sending them over the cleartext tunnel to the proxy.
- The attack works even with --anyauth/CURLAUTH_ANY, which is documented to withhold credentials until challenged by the origin — but the proxy manufactures the challenge itself.
- The PoC reproduces the leak: the malicious proxy observes 'Authorization: Basic' on the tunneled request only when it injects the 401 during CONNECT.
How this analysis ran 5 claims · 13 citations verified
Checked against curl master on 2026-09-03 (e26f6e408a80). Test evaluation split. Citation verification checks that a referenced line was in the evidence; it does not prove the model interpreted it correctly.
Review a draft reply to the reporter
Edit and verify before sending.
Thank you for the detailed report and reproducible PoC. The code confirms the flaw: during CONNECT tunnel negotiation, both H1 and H2/H3 response handlers treat a 401 WWW-Authenticate from the proxy as an origin challenge (proxy=false), poisoning authhost and causing origin credentials to be sent to the proxy on retry. This bypasses --anyauth's protection. We'll work on a fix that tracks tunnel-negotiation state and prevents origin auth state updates from proxy-controlled 401 responses during CONNECT.
Inspect all claims and source code 5 claims · 16 code excerpts
Report claims
The CONNECT-response handlers decide whether a header applies to the proxy or the origin purely by status code (401 vs 407), without checking if the response is part of tunnel negotiation.
Read the reasoning
Both CONNECT response handlers (H2/H3 in http_proxy.c and H1 in cf-h1-proxy.c) decide proxy vs origin scope solely by comparing the status code to 401 or 407. No additional check exists for whether the response is part of an ongoing CONNECT tunnel negotiation.
The flaw occurs in the CONNECT tunnel response parsing code in lib/http_proxy.c and lib/cf-h1-proxy.c.
Read the reasoning
The cited functions are the CONNECT tunnel response parsers for HTTP/2-3 and HTTP/1 respectively, and both contain the status-code-only logic.
A malicious proxy answers the CONNECT tunnel request with a 401 WWW-Authenticate header instead of the expected 407 Proxy-Authenticate.
Read the reasoning
The code has explicit branches for handling 401 WWW-Authenticate during CONNECT response processing. A malicious proxy can trigger these branches by sending 401 instead of 407.
The origin's credentials (Basic password or Kerberos ticket) are stored in data->state.authhost and then sent over the cleartext proxy tunnel, leaking them to the proxy.
Read the reasoning
When a 401 response is processed during CONNECT, proxy=false causes Curl_http_input_auth to update data->state.authhost (origin auth state). Later, output_auth_headers with proxy=false sends the origin's Basic credentials via Authorization header on the CONNECT retry, which goes to the proxy over the cleartext tunnel.
The provided PoC script starts a malicious proxy that replies with 401 WWW-Authenticate during CONNECT, causing curl to send Authorization: Basic credentials over the tunnel.
Read the reasoning
The PoC demonstrates the attack: a proxy that responds to CONNECT with 401 WWW-Authenticate causes curl to send Authorization: Basic with origin credentials over the tunnel. The control run (no 401) shows no credentials sent, confirming --anyauth works correctly without the attack.
Deterministic checks that failed
- quote only 0/4 quoted lines appear anywhere in curl at e26f6e408a80
Read the original report (excerpt)
Source code
| 466 | } |
| 467 | |
| 468 | CURLcode Curl_http_proxy_inspect_tunnel_response( |
| C2: Function Curl_http_proxy_inspect_tunnel_response handles CONNECT tunnel responses for H2/H3 | |
| 469 | struct Curl_cfilter *cf, struct Curl_easy *data, |
| 470 | struct http_resp *resp, bool udp_tunnel, |
| 471 | proxy_inspect_result *presult) |
| 472 | { |
| 473 | struct dynhds_entry *capsule_protocol = NULL; |
| 474 | struct dynhds_entry *auth_reply = NULL; |
| 475 | size_t i, header_count; |
| 476 | CURLcode result = CURLE_OK; |
| 477 | |
| 478 | DEBUGASSERT(resp); |
| 479 | |
| 480 | header_count = Curl_dynhds_count(&resp->headers); |
| 481 | if(udp_tunnel) |
| 482 | infof(data, "CONNECT-UDP Response Status %d", resp->status); |
| 483 | else |
| 484 | infof(data, "CONNECT Response Status %d", resp->status); |
| 485 | infof(data, "Response Headers (%zu total):", header_count); |
| 486 | for(i = 0; i < header_count; i++) { |
| 487 | struct dynhds_entry *entry = Curl_dynhds_getn(&resp->headers, i); |
| 488 | if(entry) |
| 489 | infof(data, " %s: %s", entry->name, entry->value); |
| 490 | } |
| 491 | |
| 492 | if(resp->status == 401) { |
| C1: Status code 401 selects WWW-Authenticate header and calls Curl_http_input_auth with proxy=false (resp->status == 407 is false) | |
| C3: Code path for 401 status exists and will be taken if proxy returns 401 | |
| 493 | auth_reply = Curl_dynhds_cget(&resp->headers, "WWW-Authenticate"); |
| 494 | } |
| 495 | else if(resp->status == 407) { |
| C1: Status code 407 selects Proxy-Authenticate header and calls Curl_http_input_auth with proxy=true | |
| 496 | auth_reply = Curl_dynhds_cget(&resp->headers, "Proxy-Authenticate"); |
| 497 | } |
| 498 | |
| 499 | if(auth_reply) { |
| 500 | CURL_TRC_CF(data, cf, "[0] CONNECT%s: fwd auth header '%s'", |
| 501 | udp_tunnel ? "-UDP" : "", auth_reply->value); |
| 502 | result = Curl_http_input_auth(data, resp->status == 407, |
| 503 | auth_reply->value); |
| 504 | if(result) |
| 505 | return result; |
| 506 | if(data->req.newurl) { |
| 507 | curlx_safefree(data->req.newurl); |
| 508 | *presult = PROXY_INSPECT_AUTH_RETRY; |
| 509 | return CURLE_OK; |
| 510 | } |
| 511 | } |
| 512 | |
| 513 | if(udp_tunnel) { |
| 514 | if(resp->status / 100 == 2) { |
| 515 | capsule_protocol = Curl_dynhds_cget(&resp->headers, |
| 516 | "capsule-protocol"); |
| 517 | if(capsule_protocol) { |
| 518 | if(!strncmp(capsule_protocol->value, "?1", 2) && |
| 519 | !capsule_protocol->value[2]) { |
| 520 | infof(data, "CONNECT-UDP tunnel established, response %d", |
| 521 | resp->status); |
| 522 | *presult = PROXY_INSPECT_OK; |
| 523 | return CURLE_OK; |
| 524 | } |
| 525 | failf(data, "Failed to establish CONNECT-UDP tunnel, response %d, " |
| 526 | "unsupported capsule-protocol value '%s'", |
| 371 | "CONNECT-UDP Response --> Proxy-Connection: close"); |
| 372 | } |
| 373 | else if(!strncmp(header, "HTTP/1.", 7) && |
| 374 | ((header[7] == '0') || (header[7] == '1')) && |
| 375 | (header[8] == ' ') && |
| 376 | ISDIGIT(header[9]) && ISDIGIT(header[10]) && ISDIGIT(header[11]) && |
| 377 | !ISDIGIT(header[12])) { |
| 378 | /* store the HTTP code from the proxy */ |
| 379 | data->info.httpproxycode = k->httpcode = |
| 380 | ((header[9] - '0') * 100) + |
| 381 | ((header[10] - '0') * 10) + |
| 382 | (header[11] - '0'); |
| 383 | CURL_TRC_CF(data, cf, "CONNECT-UDP Response --> %d", k->httpcode); |
| 384 | } |
| 385 | return result; |
| 386 | } |
| 387 | |
| 388 | static CURLcode on_resp_header(struct Curl_cfilter *cf, |
| C2: Function on_resp_header handles CONNECT response headers for H1 | |
| 389 | struct Curl_easy *data, |
| 390 | struct h1_tunnel_state *ts, |
| 391 | const char *header) |
| 392 | { |
| 393 | CURLcode result = CURLE_OK; |
| 394 | struct SingleRequest *k = &data->req; |
| 395 | (void)cf; |
| 396 | |
| 397 | if((checkprefix("WWW-Authenticate:", header) && (401 == k->httpcode)) || |
| C1: Condition checks for WWW-Authenticate with 401 or Proxy-Authenticate with 407 | |
| C3: Code path for 401 with WWW-Authenticate header exists | |
| 398 | (checkprefix("Proxy-authenticate:", header) && (407 == k->httpcode))) { |
| 399 | |
| 400 | bool proxy = (k->httpcode == 407); |
| C1: proxy boolean set purely from (k->httpcode == 407) | |
| 401 | char *auth = Curl_copy_header_value(header); |
| 402 | if(!auth) |
| 403 | return CURLE_OUT_OF_MEMORY; |
| 404 | |
| 405 | CURL_TRC_CF(data, cf, "CONNECT: fwd auth header '%s'", header); |
| 406 | result = Curl_http_input_auth(data, proxy, auth); |
| 407 | |
| 408 | curlx_free(auth); |
| 409 | |
| 410 | if(result) |
| 411 | return result; |
| 412 | } |
| 413 | else if(checkprefix("Content-Length:", header)) { |
| 414 | if(k->httpcode / 100 == 2) { |
| 415 | /* A client MUST ignore any Content-Length or Transfer-Encoding |
| 416 | header fields received in a successful response to CONNECT. |
| 417 | "Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */ |
| 418 | infof(data, "Ignoring Content-Length in CONNECT %03d response", |
| 419 | k->httpcode); |
| 420 | } |
| 421 | else { |
| 422 | const char *p = header + CURL_CSTRLEN("Content-Length:"); |
| 423 | if(curlx_str_numblanks(&p, &ts->cl)) { |
| 424 | failf(data, "Unsupported Content-Length value"); |
| 425 | return CURLE_WEIRD_SERVER_REPLY; |
| 426 | } |
| 427 | } |
| 428 | } |
| 429 | else if(Curl_compareheader(header, |
| 430 | STRCONST("Connection:"), STRCONST("close"))) |
| 431 | ts->close_connection = TRUE; |
| 1042 | #ifndef CURL_DISABLE_BEARER_AUTH |
| 1043 | static CURLcode auth_bearer(struct Curl_easy *data, |
| 1044 | struct auth *authp, |
| 1045 | uint32_t *availp) |
| 1046 | { |
| 1047 | *availp |= CURLAUTH_BEARER; |
| 1048 | authp->avail |= CURLAUTH_BEARER; |
| 1049 | if(authp->picked == CURLAUTH_BEARER) { |
| 1050 | /* We asked for Bearer authentication but got a 40X back anyway, which |
| 1051 | means our token is not valid. */ |
| 1052 | authp->avail = CURLAUTH_NONE; |
| 1053 | infof(data, "Bearer authentication problem, ignoring."); |
| 1054 | data->state.authproblem = TRUE; |
| 1055 | } |
| 1056 | return CURLE_OK; |
| 1057 | } |
| 1058 | #endif |
| 1059 | |
| 1060 | /* |
| 1061 | * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate: |
| 1062 | * headers. They are dealt with both in the transfer.c main loop and in the |
| 1063 | * proxy CONNECT loop. |
| 1064 | * |
| 1065 | * The 'auth' line ends with a null byte without CR or LF present. |
| 1066 | */ |
| 1067 | CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy, |
| 1068 | const char *auth) /* the first non-space */ |
| 1069 | { |
| 1070 | /* |
| 1071 | * This resource requires authentication |
| 1072 | */ |
| 1073 | #if defined(USE_SPNEGO) || \ |
| 1074 | defined(USE_NTLM) || \ |
| 1075 | !defined(CURL_DISABLE_DIGEST_AUTH) || \ |
| 1076 | !defined(CURL_DISABLE_BASIC_AUTH) || \ |
| 1077 | !defined(CURL_DISABLE_BEARER_AUTH) |
| 1078 | |
| 1079 | uint32_t *availp; |
| 1080 | struct auth *authp; |
| 1081 | CURLcode result = CURLE_OK; |
| 1082 | DEBUGASSERT(auth); |
| 1083 | DEBUGASSERT(data); |
| 1084 | |
| 1085 | if(proxy) { |
| 1086 | availp = &data->info.proxyauthavail; |
| 1087 | authp = &data->state.authproxy; |
| 1088 | } |
| 1089 | else { |
| C4: When proxy=false, authp points to data->state.authhost (origin auth state) | |
| 1090 | availp = &data->info.httpauthavail; |
| 1091 | authp = &data->state.authhost; |
| C4: availp points to data->info.httpauthavail (origin auth avail) | |
| 1092 | } |
| 1093 | |
| 1094 | /* |
| 1095 | * Here we check if we want the specific single authentication (using ==) and |
| 1096 | * if we do, we initiate usage of it. |
| 1097 | * |
| 1098 | * If the provided authentication is wanted as one out of several accepted |
| 1099 | * types (using &), we OR this authentication type to the authavail |
| 1100 | * variable. |
| 1101 | * |
| 1102 | * Note: |
| 1103 | * |
| 1104 | * ->picked is first set to the 'want' value (one or more bits) before the |
| 1105 | * request is sent, and then it is again set _after_ all response 401/407 |
| 1106 | * headers have been received but then only to a single preferred method |
| 1107 | * (bit). |
| 1108 | */ |
| 1109 | |
| 1110 | while(*auth) { |
| 1111 | #ifdef USE_SPNEGO |
| 1112 | if(authcmp("Negotiate", auth)) |
| 1113 | result = auth_spnego(data, proxy, auth, authp, availp); |
| 1114 | #endif |
| 1115 | #ifdef USE_NTLM |
| 1116 | if(!result && authcmp("NTLM", auth)) |
| 1117 | result = auth_ntlm(data, proxy, auth, authp, availp); |
| 1118 | #endif |
| 1119 | #ifndef CURL_DISABLE_DIGEST_AUTH |
| 1120 | if(!result && authcmp("Digest", auth)) |
| 1121 | result = auth_digest(data, proxy, auth, authp, availp); |
| 1122 | #endif |
| 1123 | #ifndef CURL_DISABLE_BASIC_AUTH |
| 1124 | if(!result && authcmp("Basic", auth)) |
| 1125 | result = auth_basic(data, authp, availp); |
| 1126 | #endif |
| 1127 | #ifndef CURL_DISABLE_BEARER_AUTH |
| 1128 | if(authcmp("Bearer", auth)) |
| 1129 | result = auth_bearer(data, authp, availp); |
| 1130 | #endif |
| 1131 | |
| 1132 | if(result) |
| 1133 | break; |
| 1134 | |
| 1135 | /* there may be multiple methods on one line, so keep reading */ |
| 1136 | auth = strchr(auth, ','); |
| 1137 | if(auth) /* if we are on a comma, skip it */ |
| 1138 | auth++; |
| 1139 | else |
| 1140 | break; |
| 1141 | curlx_str_passblanks(&auth); |
| 1142 | } |
| 1143 | return result; |
| 1144 | #else |
| 1145 | (void)data; |
| 1146 | (void)proxy; |
| 1147 | (void)auth; |
| 1148 | /* nothing to do when disabled */ |
| 1149 | return CURLE_OK; |
| 1150 | #endif |
| 1151 | } |
| 646 | static CURLcode output_auth_headers(struct Curl_easy *data, |
| 647 | struct connectdata *conn, |
| 648 | struct auth *authstatus, |
| 649 | const char *request, |
| 650 | const char *path, |
| 651 | bool proxy) |
| 652 | { |
| 653 | const char *auth = NULL; |
| 654 | CURLcode result = CURLE_OK; |
| 655 | (void)conn; |
| 656 | |
| 657 | #ifdef CURL_DISABLE_DIGEST_AUTH |
| 658 | (void)request; |
| 659 | (void)path; |
| 660 | #endif |
| 661 | #ifndef CURL_DISABLE_AWS |
| 662 | if((authstatus->picked == CURLAUTH_AWS_SIGV4) && !proxy) { |
| 663 | /* this method is never for proxy */ |
| 664 | auth = "AWS_SIGV4"; |
| 665 | result = Curl_output_aws_sigv4(data); |
| 666 | if(result) |
| 667 | return result; |
| 668 | } |
| 669 | else |
| 670 | #endif |
| 671 | #ifndef CURL_DISABLE_HTTPSIG |
| 672 | if((authstatus->picked == CURLAUTH_HTTPSIG) && !proxy) { |
| 673 | /* HTTPSIG uses its own configured key material rather than |
| 674 | data->state.creds. Do not let unrelated credentials from a |
| 675 | redirected URL bypass the cross-host auth boundary. */ |
| 676 | if(Curl_auth_allowed_to_host(data)) { |
| 677 | auth = "HTTPSIG"; |
| 678 | result = Curl_output_httpsig(data); |
| 679 | if(result) |
| 680 | return result; |
| 681 | } |
| 682 | else |
| 683 | authstatus->done = TRUE; |
| 684 | } |
| 685 | else |
| 686 | #endif |
| 687 | #ifdef USE_SPNEGO |
| 688 | if(authstatus->picked == CURLAUTH_NEGOTIATE) { |
| 689 | if( |
| 690 | #ifndef CURL_DISABLE_PROXY |
| 691 | (proxy && !Curl_checkProxyheaders(data, conn, |
| 692 | STRCONST("Proxy-authorization"))) || |
| 693 | #endif |
| 694 | (!proxy && !Curl_checkheaders(data, STRCONST("Authorization")))) { |
| 695 | auth = "Negotiate"; |
| 696 | result = Curl_output_negotiate(data, conn, proxy); |
| 697 | if(result) |
| 698 | return result; |
| 699 | } |
| 700 | else |
| 701 | authstatus->done = TRUE; |
| 702 | } |
| 703 | else |
| 704 | #endif |
| 705 | #ifdef USE_NTLM |
| 706 | if(authstatus->picked == CURLAUTH_NTLM) { |
| 707 | auth = "NTLM"; |
| 708 | result = Curl_output_ntlm(data, proxy); |
| 709 | if(result) |
| 710 | return result; |
| 711 | } |
| 712 | else |
| 713 | #endif |
| 714 | #ifndef CURL_DISABLE_DIGEST_AUTH |
| 715 | if(authstatus->picked == CURLAUTH_DIGEST) { |
| 716 | auth = "Digest"; |
| 717 | result = Curl_output_digest(data, |
| 718 | proxy, |
| 719 | (const unsigned char *)request, |
| 720 | (const unsigned char *)path); |
| 721 | if(result) |
| 722 | return result; |
| 723 | } |
| 724 | else |
| 725 | #endif |
| 726 | #ifndef CURL_DISABLE_BASIC_AUTH |
| 727 | if(authstatus->picked == CURLAUTH_BASIC) { |
| C4: output_auth_headers Basic branch checks authstatus->picked == CURLAUTH_BASIC | |
| 728 | /* Basic */ |
| 729 | if( |
| 730 | #ifndef CURL_DISABLE_PROXY |
| 731 | (proxy && conn->http_proxy.creds && |
| 732 | Curl_creds_has_user_or_pass(conn->http_proxy.creds) && |
| 733 | !Curl_checkProxyheaders(data, conn, |
| 734 | STRCONST("Proxy-authorization"))) || |
| 735 | #endif |
| 736 | (!proxy && data->state.creds && |
| C4: When proxy=false, uses data->state.creds (origin credentials) and emits Authorization header | |
| 737 | Curl_creds_has_user_or_pass(data->state.creds) && |
| 738 | !Curl_checkheaders(data, STRCONST("Authorization")))) { |
| 739 | auth = "Basic"; |
| 740 | result = http_output_basic(data, conn, proxy); |
| 741 | if(result) |
| 742 | return result; |
| 743 | } |
| 744 | |
| 745 | /* NOTE: this function should set 'done' TRUE, as the other auth |
| 746 | functions work that way */ |
| 747 | authstatus->done = TRUE; |
| 748 | } |
| 749 | #endif |
| 750 | #ifndef CURL_DISABLE_BEARER_AUTH |
| 751 | if(authstatus->picked == CURLAUTH_BEARER) { |
| 752 | /* Bearer */ |
| 753 | if(!proxy && Curl_creds_has_oauth_bearer(data->state.creds) && |
| 754 | !Curl_checkheaders(data, STRCONST("Authorization"))) { |
| 755 | auth = "Bearer"; |
| 756 | result = http_output_bearer(data); |
| 757 | if(result) |
| 758 | return result; |
| 759 | } |
| 760 | |
| 761 | /* NOTE: this function should set 'done' TRUE, as the other auth |
| 762 | functions work that way */ |
| 763 | authstatus->done = TRUE; |
| 764 | } |
| 765 | #endif |
| 766 | |
| 767 | if(auth) { |
| 768 | #ifndef CURL_DISABLE_PROXY |
| 769 | if(proxy) |
| 770 | data->info.proxyauthpicked = authstatus->picked; |
| 771 | else |
| 772 | data->info.httpauthpicked = authstatus->picked; |
| 773 | infof(data, "%s auth using %s with user '%s'", |
| 774 | proxy ? "Proxy" : "Server", auth, |
| 775 | proxy ? (conn->http_proxy.creds ? |
| 776 | conn->http_proxy.creds->user : "") : |
| 777 | (data->state.creds ? |
| 778 | data->state.creds->user : "")); |
| 779 | #else |
| 780 | (void)proxy; |
| 781 | infof(data, "Server auth using %s with user '%s'", |
| 782 | auth, data->state.creds ? |
| 783 | data->state.creds->user : ""); |
| 784 | #endif |
| 785 | authstatus->multipass = !authstatus->done; |
| 786 | } |
| 787 | else { |
| 788 | authstatus->multipass = FALSE; |
| 789 | if(proxy) |
| 790 | data->info.proxyauthpicked = 0; |
| 791 | else |
| 792 | data->info.httpauthpicked = 0; |
| 793 | } |
| 794 | |
| 795 | return result; |
| 796 | } |
| 252 | static CURLcode http_output_basic(struct Curl_easy *data, |
| 253 | struct connectdata *conn, bool proxy) |
| 254 | { |
| 255 | size_t size = 0; |
| 256 | char *authorization = NULL; |
| 257 | char **p_hd; |
| 258 | CURLcode result; |
| 259 | struct Curl_creds *creds = NULL; |
| 260 | char *out; |
| 261 | |
| 262 | /* credentials are unique per transfer for HTTP, do not use the ones for the |
| 263 | connection */ |
| 264 | if(proxy) { |
| 265 | #ifndef CURL_DISABLE_PROXY |
| 266 | p_hd = &data->req.hd_proxy_auth; |
| 267 | creds = conn->http_proxy.creds; |
| 268 | #else |
| 269 | (void)conn; |
| 270 | return CURLE_NOT_BUILT_IN; |
| 271 | #endif |
| 272 | } |
| 273 | else { |
| 274 | p_hd = &data->req.hd_auth; |
| 275 | creds = data->state.creds; |
| 276 | } |
| 277 | |
| 278 | if(!creds) { |
| 279 | DEBUGASSERT(0); |
| 280 | return CURLE_FAILED_INIT; |
| 281 | } |
| 282 | |
| 283 | out = curl_maprintf("%s:%s", creds->user, creds->passwd); |
| 284 | if(!out) |
| 285 | return CURLE_OUT_OF_MEMORY; |
| 286 | |
| 287 | result = curlx_base64_encode((uint8_t *)out, strlen(out), |
| 288 | &authorization, &size); |
| 289 | if(result) |
| 290 | goto fail; |
| 291 | |
| 292 | if(!authorization) { |
| 293 | result = CURLE_REMOTE_ACCESS_DENIED; |
| 294 | goto fail; |
| 295 | } |
| 296 | |
| 297 | curlx_free(*p_hd); |
| 298 | *p_hd = curl_maprintf("%sAuthorization: Basic %s\r\n", |
| C4: http_output_basic emits 'Authorization: Basic' when proxy=false, not 'Proxy-Authorization' | |
| 299 | proxy ? "Proxy-" : "", |
| 300 | authorization); |
| 301 | curlx_free(authorization); |
| 302 | if(!*p_hd) { |
| 303 | result = CURLE_OUT_OF_MEMORY; |
| 304 | goto fail; |
| 305 | } |
| 306 | |
| 307 | fail: |
| 308 | curlx_free(out); |
| 309 | return result; |
| 310 | } |
Show 3 lines (not cited by the judge)
| 850 | #define CURLAUTH_ANY ((~(CURLAUTH_DIGEST_IE | \ |
| 851 | CURLAUTH_HTTPSIG)) & \ |
| 852 | ((unsigned long)0xffffffff)) |
Show 1 lines (not cited by the judge)
| 833 | #define CURLAUTH_BASIC (((unsigned long)1) << 0) |
Show 16 lines (not cited by the judge)
| 84 | char *Curl_checkheaders(const struct Curl_easy *data, |
| 85 | const char *thisheader, |
| 86 | const size_t thislen) |
| 87 | { |
| 88 | struct curl_slist *head; |
| 89 | DEBUGASSERT(thislen); |
| 90 | DEBUGASSERT(thisheader[thislen - 1] != ':'); |
| 91 | |
| 92 | for(head = data->set.headers; head; head = head->next) { |
| 93 | if(curl_strnequal(head->data, thisheader, thislen) && |
| 94 | Curl_headersep(head->data[thislen])) |
| 95 | return head->data; |
| 96 | } |
| 97 | |
| 98 | return NULL; |
| 99 | } |
Show 15 lines (not cited by the judge)
| 227 | char *Curl_copy_header_value(const char *header) |
| 228 | { |
| 229 | struct Curl_str out; |
| 230 | |
| 231 | /* find the end of the header name */ |
| 232 | if(!curlx_str_until(&header, &out, MAX_HTTP_RESP_HEADER_SIZE, ':') && |
| 233 | !curlx_str_single(&header, ':')) { |
| 234 | curlx_str_untilnl(&header, &out, MAX_HTTP_RESP_HEADER_SIZE); |
| 235 | curlx_str_trimblanks(&out); |
| 236 | return curlx_memdup0(curlx_str(&out), curlx_strlen(&out)); |
| 237 | } |
| 238 | /* bad input, should never happen */ |
| 239 | DEBUGASSERT(0); |
| 240 | return NULL; |
| 241 | } |
Show 2 lines (not cited by the judge)
| 77 | #define Curl_creds_has_user_or_pass(c) \ |
| 78 | ((c) && ((c)->user[0] || (c)->passwd[0])) |
Show 4 lines (not cited by the judge)
| 126 | struct dynhds_entry *Curl_dynhds_cget(struct dynhds *dynhds, const char *name) |
| 127 | { |
| 128 | return Curl_dynhds_get(dynhds, name, strlen(name)); |
| 129 | } |
Show 1 lines (not cited by the judge)
| 1297 | #define STRCONST(x) x, CURL_CSTRLEN(x) |
Show 30 lines (not cited by the judge)
| 930 | static CURLcode auth_spnego(struct Curl_easy *data, |
| 931 | bool proxy, |
| 932 | const char *auth, |
| 933 | struct auth *authp, |
| 934 | uint32_t *availp) |
| 935 | { |
| 936 | if((authp->avail & CURLAUTH_NEGOTIATE) || Curl_auth_is_spnego_supported()) { |
| 937 | *availp |= CURLAUTH_NEGOTIATE; |
| 938 | authp->avail |= CURLAUTH_NEGOTIATE; |
| 939 | |
| 940 | if(authp->picked == CURLAUTH_NEGOTIATE) { |
| 941 | struct connectdata *conn = data->conn; |
| 942 | CURLcode result = Curl_input_negotiate(data, conn, proxy, auth); |
| 943 | curlnegotiate *negstate = proxy ? &conn->proxy_negotiate_state : |
| 944 | &conn->http_negotiate_state; |
| 945 | if(!result) { |
| 946 | curlx_free(data->req.newurl); |
| 947 | data->req.newurl = Curl_bufref_dup(&data->state.url); |
| 948 | if(!data->req.newurl) |
| 949 | return CURLE_OUT_OF_MEMORY; |
| 950 | data->state.authproblem = FALSE; |
| 951 | /* we received a GSS auth token and we dealt with it fine */ |
| 952 | *negstate = GSS_AUTHRECV; |
| 953 | } |
| 954 | else |
| 955 | data->state.authproblem = TRUE; |
| 956 | } |
| 957 | } |
| 958 | return CURLE_OK; |
| 959 | } |
Show 1 lines (not cited by the judge)
| 49 | #define checkprefix(a, b) curl_strnequal(b, STRCONST(a)) |
Show 1 lines (not cited by the judge)
| 1006 | # define false 0 |
Show 9 lines (not cited by the judge)
| 273 | int main(void) |
| 274 | { |
| 275 | size_t i; |
| 276 | |
| 277 | for(i = 0; i < CURL_ARRAYSIZE(disabled); i++) |
| 278 | puts(disabled[i]); |
| 279 | |
| 280 | return 0; |
| 281 | } |