CVE-2026-3783: token leak with redirect and netrc
What the report claims
When using --oauth2-bearer with --netrc and curl follows a redirect, the bearer token leaks to the redirect target because the netrc bypass at lib/http.c:822 skips Curl_auth_allowed_to_host() for bearer tokens.
Compare with curl's recorded outcome
Known vulnerability
A real vulnerability: CVE-2026-3783 token leak with redirect and netrc
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 netrc bypass at lib/http.c:822-827 unconditionally skips Curl_auth_allowed_to_host() when conn->bits.netrc is set
- The bearer token output path in output_auth_headers (lib/http.c:705-713) has no host check of its own
- Redirect handling (lib/http.c:1254-1257) clears user/password but not STRING_BEARER or authhost->picked
- Custom -H Authorization headers are correctly protected at lib/http.c:1828-1833 without a netrc bypass, confirming the inconsistency
- A user with --oauth2-bearer and --netrc (including a 'default' netrc entry matching all hosts) will leak their token to any redirect target
How this analysis ran 6 claims · 5 citations verified
Checked against curl master on 2026-03-03 (7079f1d39c16). Dev 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 reproduction. The code confirms the netrc bypass at lib/http.c:822-827 skips the host check, the bearer path at lib/http.c:705-713 lacks its own check, and redirects don't clear the bearer token. This is a valid token leak. We will prepare a fix along the lines of your Option A (adding Curl_auth_allowed_to_host() inside the bearer block) or Option B (excluding bearer from the netrc bypass).
Inspect all claims and source code 6 claims · 12 code excerpts
Report claims
The netrc bypass at lib/http.c:822 skips Curl_auth_allowed_to_host() allowing bearer tokens to leak to redirect targets
Read the reasoning
The code at lib/http.c:822-827 explicitly shows that when conn->bits.netrc is set, the Curl_auth_allowed_to_host() check is bypassed via OR condition, allowing output_auth_headers to be called for any host.
The bearer token output path at lib/http.c:704-714 does not perform Curl_auth_allowed_to_host() check
Read the reasoning
In output_auth_headers, the CURLAUTH_BEARER case (lines 705-713) lacks any host authorization check, unlike other auth types that are gated by the caller's check at line 822.
Using --oauth2-bearer with --netrc and following a redirect causes the token to be sent to the redirect target
Read the reasoning
The redirect handling code frees user/password credentials but leaves the bearer token string and the picked auth method intact, so the token remains available for the next request.
Bearer token is leaked to the redirect target host
Read the reasoning
The three code locations form a complete path: netrc bypass allows auth headers to be generated for the redirect host, the bearer output path emits the token without verifying the host, and the redirect logic fails to clear the token.
Test with curl --oauth2-bearer "SECRET_TOKEN" --netrc-file /tmp/test-netrc -L http://127.0.0.1:8080/redirect shows token in redirect server request
Read the reasoning
The reproduction script is external to curl's codebase; the provided code supports the described behavior but the test execution cannot be verified from source alone.
Custom -H Authorization header is correctly stripped via lib/http.c:1828-1833 which uses Curl_auth_allowed_to_host() WITHOUT netrc bypass
Read the reasoning
The custom header output path correctly calls Curl_auth_allowed_to_host() without any netrc exception, confirming the report's three-way comparison.
Deterministic checks that failed
- line none of Curl_auth_allowed_to_host, output_auth_headers, Curl_checkheaders, STRCONST appear near line 444 at 7079f1d39c16; it reads: 'const char *oauth_bearer ='
- line none of Curl_auth_allowed_to_host, output_auth_headers, Curl_checkheaders, STRCONST appear near line 444 at 7079f1d39c16; it reads: 'const char *oauth_bearer ='
- quote 1 of 3 quoted lines appear nowhere in curl, e.g. '|| (conn->bits.netrc && !(authhost->picked & CURLAUTH_BEARER'
What the report says about other projects
not addressed The Dec 2025 SASL fix (commit 1a822275d3, PR #19933) patched lib/curl_sasl.c but left the HTTP bearer path at lib/http.c:704-714 unprotected
Read the original report (excerpt)
Source code
| 795 | want one, and if this is one single bit it will be used instantly. */ |
| 796 | authhost->picked = authhost->want; |
| 797 | |
| 798 | if(authproxy->want && !authproxy->picked) |
| 799 | /* The app has selected one or more methods, but none has been picked so |
| 800 | far by a proxy round-trip. Then we set the picked one to the want one, |
| 801 | and if this is one single bit it will be used instantly. */ |
| 802 | authproxy->picked = authproxy->want; |
| 803 | |
| 804 | #ifndef CURL_DISABLE_PROXY |
| 805 | /* Send proxy authentication header if needed */ |
| 806 | if(conn->bits.httpproxy && |
| 807 | (conn->bits.tunnel_proxy == (curl_bit)proxytunnel)) { |
| 808 | result = output_auth_headers(data, conn, authproxy, request, path, TRUE); |
| 809 | if(result) |
| 810 | return result; |
| 811 | } |
| 812 | else |
| 813 | #else |
| 814 | (void)proxytunnel; |
| 815 | #endif /* CURL_DISABLE_PROXY */ |
| 816 | /* we have no proxy so let's pretend we are done authenticating |
| 817 | with it */ |
| 818 | authproxy->done = TRUE; |
| 819 | |
| 820 | /* To prevent the user+password to get sent to other than the original host |
| 821 | due to a location-follow */ |
| 822 | if(Curl_auth_allowed_to_host(data) |
| C1: The condition at lines 822-827 shows: if(Curl_auth_allowed_to_host(data) || conn->bits.netrc) — the netrc bit bypasses the host check entirely | |
| C4: Combined effect: netrc bypass (C1) + bearer path lacks host check (C2) + bearer not cleared on redirect (C3) = token sent to redirect target | |
| 823 | #ifndef CURL_DISABLE_NETRC |
| 824 | || conn->bits.netrc |
| 825 | #endif |
| 826 | ) |
| 827 | result = output_auth_headers(data, conn, authhost, request, path, FALSE); |
| 828 | else |
| 829 | authhost->done = TRUE; |
| 830 | |
| 831 | if(((authhost->multipass && !authhost->done) || |
| 832 | (authproxy->multipass && !authproxy->done)) && |
| 833 | (httpreq != HTTPREQ_GET) && |
| 834 | (httpreq != HTTPREQ_HEAD)) { |
| 835 | /* Auth is required and we are not authenticated yet. Make a PUT or POST |
| 836 | with content-length zero as a "probe". */ |
| 837 | data->req.authneg = TRUE; |
| 838 | } |
| 839 | else |
| 840 | data->req.authneg = FALSE; |
| 841 | |
| 842 | return result; |
| 843 | } |
| 844 | |
| 845 | #else |
| 846 | /* when disabled */ |
| 847 | CURLcode Curl_http_output_auth(struct Curl_easy *data, |
| 848 | struct connectdata *conn, |
| 849 | const char *request, |
| 850 | Curl_HttpReq httpreq, |
| 851 | const char *path, |
| 852 | bool proxytunnel) |
| 627 | static CURLcode output_auth_headers(struct Curl_easy *data, |
| 628 | struct connectdata *conn, |
| 629 | struct auth *authstatus, |
| 630 | const char *request, |
| 631 | const char *path, |
| 632 | bool proxy) |
| 633 | { |
| 634 | const char *auth = NULL; |
| 635 | CURLcode result = CURLE_OK; |
| 636 | (void)conn; |
| 637 | |
| 638 | #ifdef CURL_DISABLE_DIGEST_AUTH |
| 639 | (void)request; |
| 640 | (void)path; |
| 641 | #endif |
| 642 | #ifndef CURL_DISABLE_AWS |
| 643 | if((authstatus->picked == CURLAUTH_AWS_SIGV4) && !proxy) { |
| 644 | /* this method is never for proxy */ |
| 645 | auth = "AWS_SIGV4"; |
| 646 | result = Curl_output_aws_sigv4(data); |
| 647 | if(result) |
| 648 | return result; |
| 649 | } |
| 650 | else |
| 651 | #endif |
| 652 | #ifdef USE_SPNEGO |
| 653 | if(authstatus->picked == CURLAUTH_NEGOTIATE) { |
| 654 | auth = "Negotiate"; |
| 655 | result = Curl_output_negotiate(data, conn, proxy); |
| 656 | if(result) |
| 657 | return result; |
| 658 | } |
| 659 | else |
| 660 | #endif |
| 661 | #ifdef USE_NTLM |
| 662 | if(authstatus->picked == CURLAUTH_NTLM) { |
| 663 | auth = "NTLM"; |
| 664 | result = Curl_output_ntlm(data, proxy); |
| 665 | if(result) |
| 666 | return result; |
| 667 | } |
| 668 | else |
| 669 | #endif |
| 670 | #ifndef CURL_DISABLE_DIGEST_AUTH |
| 671 | if(authstatus->picked == CURLAUTH_DIGEST) { |
| 672 | auth = "Digest"; |
| 673 | result = Curl_output_digest(data, |
| 674 | proxy, |
| 675 | (const unsigned char *)request, |
| 676 | (const unsigned char *)path); |
| 677 | if(result) |
| 678 | return result; |
| 679 | } |
| 680 | else |
| 681 | #endif |
| 682 | #ifndef CURL_DISABLE_BASIC_AUTH |
| 683 | if(authstatus->picked == CURLAUTH_BASIC) { |
| 684 | /* Basic */ |
| 685 | if( |
| 686 | #ifndef CURL_DISABLE_PROXY |
| 687 | (proxy && conn->bits.proxy_user_passwd && |
| 688 | !Curl_checkProxyheaders(data, conn, |
| 689 | STRCONST("Proxy-authorization"))) || |
| 690 | #endif |
| 691 | (!proxy && data->state.aptr.user && |
| 692 | !Curl_checkheaders(data, STRCONST("Authorization")))) { |
| 693 | auth = "Basic"; |
| 694 | result = http_output_basic(data, proxy); |
| 695 | if(result) |
| 696 | return result; |
| 697 | } |
| 698 | |
| 699 | /* NOTE: this function should set 'done' TRUE, as the other auth |
| 700 | functions work that way */ |
| 701 | authstatus->done = TRUE; |
| 702 | } |
| 703 | #endif |
| 704 | #ifndef CURL_DISABLE_BEARER_AUTH |
| 705 | if(authstatus->picked == CURLAUTH_BEARER) { |
| C2: The bearer auth block at lines 705-713 checks only !proxy, data->set.str[STRING_BEARER], and !Curl_checkheaders — no Curl_auth_allowed_to_host() call | |
| 706 | /* Bearer */ |
| 707 | if(!proxy && data->set.str[STRING_BEARER] && |
| 708 | !Curl_checkheaders(data, STRCONST("Authorization"))) { |
| 709 | auth = "Bearer"; |
| 710 | result = http_output_bearer(data); |
| 711 | if(result) |
| 712 | return result; |
| 713 | } |
| 714 | |
| 715 | /* NOTE: this function should set 'done' TRUE, as the other auth |
| 716 | functions work that way */ |
| 717 | authstatus->done = TRUE; |
| 718 | } |
| 719 | #endif |
| 720 | |
| 721 | if(auth) { |
| 722 | #ifndef CURL_DISABLE_PROXY |
| 723 | infof(data, "%s auth using %s with user '%s'", |
| 724 | proxy ? "Proxy" : "Server", auth, |
| 725 | proxy ? (data->state.aptr.proxyuser ? |
| 726 | data->state.aptr.proxyuser : "") : |
| 727 | (data->state.aptr.user ? |
| 728 | data->state.aptr.user : "")); |
| 729 | #else |
| 730 | (void)proxy; |
| 731 | infof(data, "Server auth using %s with user '%s'", |
| 732 | auth, data->state.aptr.user ? |
| 733 | data->state.aptr.user : ""); |
| 734 | #endif |
| 735 | authstatus->multipass = !authstatus->done; |
| 736 | } |
| 737 | else |
| 738 | authstatus->multipass = FALSE; |
| 739 | |
| 740 | return result; |
| 741 | } |
| 1803 | /* a Host: header was sent already, do not pass on any custom |
| 1804 | Host: header as that will produce *two* in the same |
| 1805 | request! */ |
| 1806 | curlx_str_casecompare(&name, "Host")) |
| 1807 | ; |
| 1808 | else if(data->state.httpreq == HTTPREQ_POST_FORM && |
| 1809 | /* this header (extended by formdata.c) is sent later */ |
| 1810 | curlx_str_casecompare(&name, "Content-Type")) |
| 1811 | ; |
| 1812 | else if(data->state.httpreq == HTTPREQ_POST_MIME && |
| 1813 | /* this header is sent later */ |
| 1814 | curlx_str_casecompare(&name, "Content-Type")) |
| 1815 | ; |
| 1816 | else if(data->req.authneg && |
| 1817 | /* while doing auth neg, do not allow the custom length since |
| 1818 | we will force length zero then */ |
| 1819 | curlx_str_casecompare(&name, "Content-Length")) |
| 1820 | ; |
| 1821 | else if(curlx_str_casecompare(&name, "Connection")) |
| 1822 | /* Connection headers are handled specially */ |
| 1823 | ; |
| 1824 | else if((httpversion >= 20) && |
| 1825 | curlx_str_casecompare(&name, "Transfer-Encoding")) |
| 1826 | /* HTTP/2 does not support chunked requests */ |
| 1827 | ; |
| 1828 | else if((curlx_str_casecompare(&name, "Authorization") || |
| C6: Lines 1828-1833 show custom Authorization/Cookie headers are suppressed when curlx_str_casecompare matches 'Authorization' or 'Cookie', the header is omitted if !Curl_auth_allowed_to_host(data) — no netrc bypass here | |
| 1829 | curlx_str_casecompare(&name, "Cookie")) && |
| 1830 | /* be careful of sending this potentially sensitive header to |
| 1831 | other hosts */ |
| 1832 | !Curl_auth_allowed_to_host(data)) |
| 1833 | ; |
| 1834 | else if(blankheader) |
| 1835 | result = curlx_dyn_addf(req, "%.*s:\r\n", (int)curlx_strlen(&name), |
| 1836 | curlx_str(&name)); |
| 1837 | else |
| 1838 | result = curlx_dyn_addf(req, "%s\r\n", origp); |
| 1839 | |
| 1840 | if(result) |
| 1841 | return result; |
| 1842 | } |
| 1843 | } |
| 1844 | |
| 1845 | return CURLE_OK; |
| 1846 | } |
| 1847 | |
| 1848 | #ifndef CURL_DISABLE_PARSEDATE |
| 1849 | CURLcode Curl_add_timecondition(struct Curl_easy *data, |
| 1850 | struct dynbuf *req) |
| 1851 | { |
| 1852 | const struct tm *tm; |
| 1853 | struct tm keeptime; |
| 1854 | CURLcode result; |
| 1855 | char datestr[80]; |
| 1856 | const char *condp; |
| 1857 | size_t len; |
| 1858 |
| 1229 | port = (int)value; |
| 1230 | curlx_free(portnum); |
| 1231 | } |
| 1232 | if(port != data->info.conn_remote_port) { |
| 1233 | infof(data, "Clear auth, redirects to port from %u to %u", |
| 1234 | data->info.conn_remote_port, port); |
| 1235 | clear = TRUE; |
| 1236 | } |
| 1237 | else { |
| 1238 | char *scheme; |
| 1239 | const struct Curl_scheme *p; |
| 1240 | uc = curl_url_get(data->state.uh, CURLUPART_SCHEME, &scheme, 0); |
| 1241 | if(uc) { |
| 1242 | curlx_free(follow_url); |
| 1243 | return Curl_uc_to_curlcode(uc); |
| 1244 | } |
| 1245 | |
| 1246 | p = Curl_get_scheme(scheme); |
| 1247 | if(p && (p->protocol != data->info.conn_protocol)) { |
| 1248 | infof(data, "Clear auth, redirects scheme from %s to %s", |
| 1249 | data->info.conn_scheme, scheme); |
| 1250 | clear = TRUE; |
| 1251 | } |
| 1252 | curlx_free(scheme); |
| 1253 | } |
| 1254 | if(clear) { |
| C3: Lines 1254-1257 clear user and passwd on redirect but do not clear STRING_BEARER or reset authhost->picked | |
| 1255 | Curl_safefree(data->state.aptr.user); |
| 1256 | Curl_safefree(data->state.aptr.passwd); |
| 1257 | } |
| 1258 | } |
| 1259 | } |
| 1260 | DEBUGASSERT(follow_url); |
| 1261 | |
| 1262 | if(type == FOLLOW_FAKE) { |
| 1263 | /* we are only figuring out the new URL if we would have followed locations |
| 1264 | but now we are done so we can get out! */ |
| 1265 | data->info.wouldredirect = follow_url; |
| 1266 | |
| 1267 | if(reachedmax) { |
| 1268 | failf(data, "Maximum (%d) redirects followed", data->set.maxredirs); |
| 1269 | return CURLE_TOO_MANY_REDIRECTS; |
| 1270 | } |
| 1271 | return CURLE_OK; |
| 1272 | } |
| 1273 | |
| 1274 | if(disallowport) |
| 1275 | data->state.allow_port = FALSE; |
| 1276 | |
| 1277 | Curl_bufref_set(&data->state.url, follow_url, 0, curl_free); |
| 1278 | rewind_result = Curl_req_soft_reset(&data->req, data); |
| 1279 | infof(data, "Issue another request to this URL: '%s'", follow_url); |
| 1280 | if((data->set.http_follow_mode == CURLFOLLOW_FIRSTONLY) && |
| 1281 | data->set.str[STRING_CUSTOMREQUEST] && |
| 1282 | !data->state.http_ignorecustom) { |
Show 10 lines (not cited by the judge)
| 138 | bool Curl_auth_allowed_to_host(struct Curl_easy *data) |
| 139 | { |
| 140 | struct connectdata *conn = data->conn; |
| 141 | return !data->state.this_is_a_follow || |
| 142 | data->set.allow_auth_to_other_hosts || |
| 143 | (data->state.first_host && |
| 144 | curl_strequal(data->state.first_host, conn->host.name) && |
| 145 | (data->state.first_remote_port == conn->remote_port) && |
| 146 | (data->state.first_remote_protocol == conn->scheme->protocol)); |
| 147 | } |
Show 10 lines (not cited by the judge)
| 138 | bool Curl_auth_allowed_to_host(struct Curl_easy *data) |
| 139 | { |
| 140 | struct connectdata *conn = data->conn; |
| 141 | return !data->state.this_is_a_follow || |
| 142 | data->set.allow_auth_to_other_hosts || |
| 143 | (data->state.first_host && |
| 144 | curl_strequal(data->state.first_host, conn->host.name) && |
| 145 | (data->state.first_remote_port == conn->remote_port) && |
| 146 | (data->state.first_remote_protocol == conn->handler->protocol)); |
| 147 | } |
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 5 lines (not cited by the judge)
| 1314 | #define Curl_safefree(ptr) \ |
| 1315 | do { \ |
| 1316 | curlx_free(ptr); \ |
| 1317 | (ptr) = NULL; \ |
| 1318 | } while(0) |
Show 1 lines (not cited by the judge)
| 1280 | #define STRCONST(x) x, sizeof(x) - 1 |
Show 5 lines (not cited by the judge)
| 239 | int curlx_str_casecompare(struct Curl_str *str, const char *check) |
| 240 | { |
| 241 | size_t clen = check ? strlen(check) : 0; |
| 242 | return ((str->len == clen) && curl_strnequal(str->str, check, clen)); |
| 243 | } |
Show 18 lines (not cited by the judge)
| 308 | static CURLcode http_output_bearer(struct Curl_easy *data) |
| 309 | { |
| 310 | char **userp; |
| 311 | CURLcode result = CURLE_OK; |
| 312 | |
| 313 | userp = &data->state.aptr.userpwd; |
| 314 | curlx_free(*userp); |
| 315 | *userp = curl_maprintf("Authorization: Bearer %s\r\n", |
| 316 | data->set.str[STRING_BEARER]); |
| 317 | |
| 318 | if(!*userp) { |
| 319 | result = CURLE_OUT_OF_MEMORY; |
| 320 | goto fail; |
| 321 | } |
| 322 | |
| 323 | fail: |
| 324 | return result; |
| 325 | } |
Show 114 lines (not cited by the judge)
| 648 | static CURLcode output_auth_headers(struct Curl_easy *data, |
| 649 | struct connectdata *conn, |
| 650 | struct auth *authstatus, |
| 651 | const char *request, |
| 652 | const char *path, |
| 653 | bool proxy) |
| 654 | { |
| 655 | const char *auth = NULL; |
| 656 | CURLcode result = CURLE_OK; |
| 657 | (void)conn; |
| 658 | |
| 659 | #ifdef CURL_DISABLE_DIGEST_AUTH |
| 660 | (void)request; |
| 661 | (void)path; |
| 662 | #endif |
| 663 | #ifndef CURL_DISABLE_AWS |
| 664 | if((authstatus->picked == CURLAUTH_AWS_SIGV4) && !proxy) { |
| 665 | /* this method is never for proxy */ |
| 666 | auth = "AWS_SIGV4"; |
| 667 | result = Curl_output_aws_sigv4(data); |
| 668 | if(result) |
| 669 | return result; |
| 670 | } |
| 671 | else |
| 672 | #endif |
| 673 | #ifdef USE_SPNEGO |
| 674 | if(authstatus->picked == CURLAUTH_NEGOTIATE) { |
| 675 | auth = "Negotiate"; |
| 676 | result = Curl_output_negotiate(data, conn, proxy); |
| 677 | if(result) |
| 678 | return result; |
| 679 | } |
| 680 | else |
| 681 | #endif |
| 682 | #ifdef USE_NTLM |
| 683 | if(authstatus->picked == CURLAUTH_NTLM) { |
| 684 | auth = "NTLM"; |
| 685 | result = Curl_output_ntlm(data, proxy); |
| 686 | if(result) |
| 687 | return result; |
| 688 | } |
| 689 | else |
| 690 | #endif |
| 691 | #ifndef CURL_DISABLE_DIGEST_AUTH |
| 692 | if(authstatus->picked == CURLAUTH_DIGEST) { |
| 693 | auth = "Digest"; |
| 694 | result = Curl_output_digest(data, |
| 695 | proxy, |
| 696 | (const unsigned char *)request, |
| 697 | (const unsigned char *)path); |
| 698 | if(result) |
| 699 | return result; |
| 700 | } |
| 701 | else |
| 702 | #endif |
| 703 | #ifndef CURL_DISABLE_BASIC_AUTH |
| 704 | if(authstatus->picked == CURLAUTH_BASIC) { |
| 705 | /* Basic */ |
| 706 | if( |
| 707 | #ifndef CURL_DISABLE_PROXY |
| 708 | (proxy && conn->bits.proxy_user_passwd && |
| 709 | !Curl_checkProxyheaders(data, conn, STRCONST("Proxy-authorization"))) || |
| 710 | #endif |
| 711 | (!proxy && data->state.aptr.user && |
| 712 | !Curl_checkheaders(data, STRCONST("Authorization")))) { |
| 713 | auth = "Basic"; |
| 714 | result = http_output_basic(data, proxy); |
| 715 | if(result) |
| 716 | return result; |
| 717 | } |
| 718 | |
| 719 | /* NOTE: this function should set 'done' TRUE, as the other auth |
| 720 | functions work that way */ |
| 721 | authstatus->done = TRUE; |
| 722 | } |
| 723 | #endif |
| 724 | #ifndef CURL_DISABLE_BEARER_AUTH |
| 725 | if(authstatus->picked == CURLAUTH_BEARER) { |
| 726 | /* Bearer */ |
| 727 | if((!proxy && data->set.str[STRING_BEARER] && |
| 728 | !Curl_checkheaders(data, STRCONST("Authorization")))) { |
| 729 | auth = "Bearer"; |
| 730 | result = http_output_bearer(data); |
| 731 | if(result) |
| 732 | return result; |
| 733 | } |
| 734 | |
| 735 | /* NOTE: this function should set 'done' TRUE, as the other auth |
| 736 | functions work that way */ |
| 737 | authstatus->done = TRUE; |
| 738 | } |
| 739 | #endif |
| 740 | |
| 741 | if(auth) { |
| 742 | #ifndef CURL_DISABLE_PROXY |
| 743 | infof(data, "%s auth using %s with user '%s'", |
| 744 | proxy ? "Proxy" : "Server", auth, |
| 745 | proxy ? (data->state.aptr.proxyuser ? |
| 746 | data->state.aptr.proxyuser : "") : |
| 747 | (data->state.aptr.user ? |
| 748 | data->state.aptr.user : "")); |
| 749 | #else |
| 750 | (void)proxy; |
| 751 | infof(data, "Server auth using %s with user '%s'", |
| 752 | auth, data->state.aptr.user ? |
| 753 | data->state.aptr.user : ""); |
| 754 | #endif |
| 755 | authstatus->multipass = !authstatus->done; |
| 756 | } |
| 757 | else |
| 758 | authstatus->multipass = FALSE; |
| 759 | |
| 760 | return result; |
| 761 | } |