✓ProveIt
Examples / Report #3993549 Saved analysis

CVE-2026-86413: Negotiate credentials sent to redirected origin

curl · 2026-09-0318.3s analysis · $0.027 in model calls

What the report claims

libcurl may send a Negotiate/Kerberos Authorization header to an unintended host after a redirect that contains userinfo in the Location header, bypassing cross-host authentication restrictions.

Compare with curl's recorded outcome

Known vulnerability

A real vulnerability: CVE-2026-86413 Negotiate credentials sent to redirected origin

Shown for comparison after analysis. The pipeline did not see this label.

ProveIt's finding

Code supports the claim

The code supports the reported flaw. A maintainer should review its impact and decide what to do next.

Why this finding?
  • The code at lib/url.c:1456-1495 extracts credentials from a redirect URL's userinfo without calling Curl_auth_allowed_to_origin, while the OPTION credential branch at lines 1428-1452 does check it.
  • The condition at lib/http.c:874 (data->state.creds || Curl_auth_allowed_to_host(data)) allows any non-NULL creds to bypass the cross-host auth guard.
  • For SPNEGO/Negotiate, the token is minted from the client's Kerberos TGT, not from the URL credentials, so even junk userinfo in the redirect is sufficient to trigger sending a valid service ticket for the attacker's host.
  • The PoC demonstrates the exploit works with a live Kerberos TGT, and the control variant (no userinfo) correctly sends no Authorization header.
  • This vulnerability exists in the current main branch (38703fe2) and was introduced by commit 8f71d0fde51 which removed the strict origin check while adding the asymmetric gating in url_set_data_creds.
How this analysis ran 5 claims · 10 citations verified

Checked against curl permalink 38703fe2610b (38703fe2610b). Dev evaluation split. Citation verification checks that a referenced line was in the evidence; it does not prove the model interpreted it correctly.

1 · Grounding
partially grounded
no model · 39 references checked out, 1 did not
2 · Claims
NVIDIA-Nemotron-3-Nano-30B-A3B
5 claims · 3598 tokens · $0.0003
3 · Evidence
14 code snippets
real curl source at 38703fe2610b · 1 docs via Tavily
4 · Judgment
Nemotron-3-Ultra-550b-a55b
20802 tokens · 14.2s · $0.0268
5 · Receipts
10 of 10 citations verified
every citation must point at code the judge was shown
Review a draft reply to the reporter

Edit and verify before sending.

Thank you for the detailed report and PoC. The vulnerability is confirmed: url_set_data_creds() extracts URL-embedded credentials on redirect without an origin check (lib/url.c:1456-1495), and Curl_http_output_auth() then bypasses the cross-host guard because data->state.creds is non-NULL (lib/http.c:874). For Negotiate, this causes a real Kerberos ticket for the attacker's host to be minted from the client's TGT and sent. We will fix this by gating the URL credential branch with Curl_auth_allowed_to_origin(), matching the OPTION branch.

Inspect all claims and source code 5 claims · 14 code excerpts

Report claims

C1flaw supported

The condition `data->state.creds || Curl_auth_allowed_to_host(data)` in `Curl_http_output_auth()` allows credentials set from a redirect URL to bypass the origin check.

Read the reasoning

The code at lib/http.c:874 shows exactly the condition described: if data->state.creds is set (non-NULL), output_auth_headers is called without requiring Curl_auth_allowed_to_host(data) to be true.

C2location supported

The origin check is performed only for credentials set via CURLOPT_USER options, not for credentials extracted from a URL's embedded userinfo.

Read the reasoning

The origin check functions are correctly implemented in vauth.c. The issue is that they are not called for URL-embedded credentials.

C3trigger supported

When a redirect's Location header contains `http://user:pass@evil.host/...`, `url_set_data_creds()` populates `data->state.creds` without invoking `Curl_auth_allowed_to_origin()`.

Read the reasoning

The URL credential extraction branch at lib/url.c:1456-1495 lacks any call to Curl_auth_allowed_to_origin, while the OPTION credential branch at lines 1428-1452 explicitly gates on it. A redirect URL with userinfo triggers the URL branch and sets data->state.creds without an origin check.

C4impact supported

A valid SPNEGO/Kerberos token for the attacker‑controlled host is sent, even though the client never intended to authenticate to that host.

Read the reasoning

For SPNEGO/Negotiate, the token is generated from the client's ambient Kerberos TGT (via GSSAPI/SSPI), not from the URL's user:pass. The presence of any userinfo in the redirect URL sets data->state.creds, which bypasses the origin check in Curl_http_output_auth, causing the real Kerberos service ticket for the attacker's host to be sent.

C5reproduction supported

A curl command that follows a redirect with userinfo in the Location header causes libcurl to emit an Authorization: Negotiate header to the redirected host.

Read the reasoning

The PoC demonstrates the exact code path: redirect with userinfo in Location -> url_set_data_creds sets data->state.creds via URL branch (no origin check) -> Curl_http_output_auth sees non-NULL creds -> calls output_auth_headers -> Negotiate path mints and sends real Kerberos ticket to attacker host. The control variant (no userinfo) sends no Authorization header.

Deterministic checks that failed

  • quote 1 of 2 quoted lines appear nowhere in curl, e.g. 'if(Curl_auth_allowed_to_host(data) || conn->bits.netrc)'
Read the original report (excerpt)

Full report on HackerOne ↗

Hi all, I found a way to make libcurl send a live SPNEGO/Kerberos `Authorization: Negotiate` token to a host the client never intended to authenticate to, bypassing the cross-host auth restriction, when following a redirect whose `Location:` header embeds userinfo (`http://user:pass@evil.host/...`). ## The bug `Curl_http_output_auth()` decides whether to attach auth headers for the current host with: ```c // lib/http.c:874 if(data->state.creds || Curl_auth_allowed_to_host(data)) result = output_auth_headers(data, conn, authhost, request, path_and_query, FALSE); ``` `Curl_auth_allowed_to_host()` is the intended cross-host guard — it's `FALSE` once you've been redirected to a different origin (unless `CURLOPT_UNRESTRICTED_AUTH` is set): ```c // lib/vauth/vauth.c:140-149 bool Curl_auth_allowed_to_host(struct Curl_easy *data) { return Curl_auth_allowed_to_origin(data, data->state.origin); } bool Curl_auth_allowed_to_origin(struct Curl_easy *data, struct Curl_peer *origin) { return data->set.allow_auth_to_other_hosts || Curl_peer_equal(data->state.initial_origin, origin); } ``` The problem is the `data->state.creds ||` in front of it. `url_set_data_creds()` runs on every URL (redirects included), and only the CURLOPT_* ("OPTION") credential branch is gated by `Curl_auth_allowed_to_origin()` — the URL-embedded-userinfo branch right below it isn't: ```c // lib/url.c:1423-1456 static CURLcode url_set_data_creds(struct Curl_easy *data, CURLU *uh) { ... if((CURL_EASY_STR(data, STRING_USERNAME) || ... ) && Curl_auth_allowed_to_origin(data, data->state.origin)) { result = Curl_creds_create(..., CREDS_OPTION, &newcreds); ... } /* Extract credentials from the URL only if there are none OR * if no CURLOPT_USER was set. */ if(!newcreds || !Curl_creds_has_user(newcreds)) { ... result = Curl_creds_merge(udecoded, pdecoded, newcreds, CREDS_URL, &newcreds); ... } ``` So a redirect to `http://user:pass@evil.host/` sets `data->state.creds` non-NULL with **no origin check at all**, which then short-circuits the guard in `Curl_http_output_auth()`. For Negotiate this is worse than it looks: the "credentials" here are never actually used — GSSAPI/SSPI mints the token from the client's ambient Kerberos TGT, not from the URL …

Source code

lib/http.clines 798–899 · lines 874-874 cited by the report; definition of Curl_http_output_auth
798CURLcode Curl_http_output_auth(struct Curl_easy *data,
799 struct connectdata *conn,
800 const char *request,
801 Curl_HttpReq httpreq,
802 const char *path,
803 const char *query,
804 bool is_connect)
805{
806 CURLcode result = CURLE_OK;
807 struct auth *authhost;
808 struct auth *authproxy;
809 const char *path_and_query = path;
810 char *tmp_str = NULL;
811
812 DEBUGASSERT(data);
813 authhost = &data->state.authhost;
814 authproxy = &data->state.authproxy;
815
816 if(
817#ifndef CURL_DISABLE_PROXY
818 (!conn->http_proxy.peer || !conn->http_proxy.creds) &&
819#endif
820#ifdef USE_SPNEGO
821 !(authhost->want & CURLAUTH_NEGOTIATE) &&
822 !(authproxy->want & CURLAUTH_NEGOTIATE) &&
823#endif
824#ifndef CURL_DISABLE_HTTPSIG
825 !(authhost->want & CURLAUTH_HTTPSIG) &&
826#endif
827 !data->state.creds) {
828 /* no authentication with no user or password */
829 authhost->done = TRUE;
830 authproxy->done = TRUE;
831 result = CURLE_OK;
832 goto out;
833 }
834
835 if(query) {
836 tmp_str = curl_maprintf("%s?%s", path, query);
837 if(!tmp_str) {
838 result = CURLE_OUT_OF_MEMORY;
839 goto out;
840 }
841 path_and_query = tmp_str;
842 }
843
844 if(authhost->want && !authhost->picked)
845 /* The app has selected one or more methods, but none has been picked
846 so far by a server round-trip. Then we set the picked one to the
847 want one, and if this is one single bit it will be used instantly. */
848 authhost->picked = authhost->want;
849
850 if(authproxy->want && !authproxy->picked)
851 /* The app has selected one or more methods, but none has been picked so
852 far by a proxy round-trip. Then we set the picked one to the want one,
853 and if this is one single bit it will be used instantly. */
854 authproxy->picked = authproxy->want;
855
856#ifndef CURL_DISABLE_PROXY
857 /* Send proxy authentication header if needed */
858 if(conn->bits.origin_is_proxy || is_connect) {
859 result = output_auth_headers(data, conn, authproxy, request,
860 path_and_query, TRUE);
861 if(result)
862 goto out;
863 }
864 else
865#else
866 (void)is_connect;
867#endif /* CURL_DISABLE_PROXY */
868 /* we have no proxy so let's pretend we are done authenticating
869 with it */
870 authproxy->done = TRUE;
871
872 /* Either we have credentials for the origin we talk to or
873 performing authentication is allowed here */
874 if(data->state.creds || Curl_auth_allowed_to_host(data))
C1: Condition `if(data->state.creds || Curl_auth_allowed_to_host(data))` allows non-NULL creds to bypass origin check
C5: data->state.creds being non-NULL triggers auth header output including Negotiate
875 result = output_auth_headers(data, conn, authhost, request,
876 path_and_query, FALSE);
877 else
878 authhost->done = TRUE;
879
880 if(((authhost->multipass && !authhost->done) ||
881 (authproxy->multipass && !authproxy->done)) &&
882 (httpreq != HTTPREQ_GET) &&
883 (httpreq != HTTPREQ_HEAD)) {
884 /* Auth is required and we are not authenticated yet. Make a PUT or POST
885 with content-length zero as a "probe". */
886 data->req.authneg = TRUE;
887 }
888 else
889 data->req.authneg = FALSE;
890
891out:
892 curlx_free(tmp_str);
893 return result;
894}
895
896#else /* !CURL_DISABLE_HTTP_AUTH */
897/* when disabled */
898CURLcode Curl_http_output_auth(struct Curl_easy *data,
899 struct connectdata *conn,
lib/vauth/vauth.clines 115–174 · lines 140-149 cited by the report
115bool Curl_auth_user_contains_domain(struct Curl_creds *creds)
116{
117 bool valid = FALSE;
118
119 if(Curl_creds_has_user(creds)) {
120 /* Check we have a domain name or UPN present */
121 const char *p = strpbrk(creds->user, "\\/@");
122
123 valid = p && (p > creds->user) &&
124 (p < (creds->user + strlen(creds->user) - 1));
125 }
126#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
127 else
128 /* User and domain are obtained from the GSS-API credentials cache or the
129 currently logged in user from Windows */
130 valid = TRUE;
131#endif
132
133 return valid;
134}
135
136/*
137 * Curl_auth_allowed_to_host() tells if authentication, cookies or other
138 * "sensitive data" can be sent to the connection's origin.
139 */
140bool Curl_auth_allowed_to_host(struct Curl_easy *data)
C2: Curl_auth_allowed_to_host calls Curl_auth_allowed_to_origin with data->state.origin
141{
142 return Curl_auth_allowed_to_origin(data, data->state.origin);
143}
144
145bool Curl_auth_allowed_to_origin(struct Curl_easy *data,
146 struct Curl_peer *origin)
147{
148 return data->set.allow_auth_to_other_hosts ||
C2: Curl_auth_allowed_to_origin returns true only if allow_auth_to_other_hosts is set or origin equals initial_origin
149 Curl_peer_equal(data->state.initial_origin, origin);
150}
151
152#ifdef USE_NTLM
153static void ntlm_conn_dtor(void *key, size_t klen, void *entry)
154{
155 struct ntlmdata *ntlm = entry;
156 (void)key;
157 (void)klen;
158 DEBUGASSERT(ntlm);
159 Curl_auth_cleanup_ntlm(ntlm);
160 curlx_free(ntlm);
161}
162
163struct ntlmdata *Curl_auth_ntlm_get(struct connectdata *conn, bool proxy)
164{
165 const char *key = proxy ? CURL_META_NTLM_PROXY_CONN : CURL_META_NTLM_CONN;
166 struct ntlmdata *ntlm = Curl_conn_meta_get(conn, key);
167 if(!ntlm) {
168 ntlm = curlx_calloc(1, sizeof(*ntlm));
169 if(!ntlm || Curl_conn_meta_set(conn, key, ntlm, ntlm_conn_dtor))
170 return NULL;
171 }
172 return ntlm;
173}
174
lib/url.clines 1398–1510 · lines 1423-1456 cited by the report; definition of url_set_data_creds
1398 goto out;
1399 /* for updated strings, we update them in the URL */
1400 uc = curl_url_set(data->state.uh, CURLUPART_USER,
1401 Curl_creds_user(*pcreds), CURLU_URLENCODE);
1402 if(!uc)
1403 uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
1404 Curl_creds_passwd(*pcreds),
1405 CURLU_URLENCODE);
1406 if(uc)
1407 result = Curl_uc_to_curlcode(uc);
1408 }
1409 else
1410 DEBUGASSERT(0);
1411 }
1412
1413#ifdef CURLVERBOSE
1414 Curl_creds_trace(data, data->state.creds, "transfer credentials");
1415#endif
1416
1417out:
1418 Curl_creds_unlink(&ncreds_out);
1419 return result;
1420}
1421#endif /* CURL_DISABLE_NETRC */
1422
1423static CURLcode url_set_data_creds(struct Curl_easy *data, CURLU *uh)
1424{
1425 struct Curl_creds *newcreds = NULL;
1426 CURLcode result = CURLE_OK;
1427
1428 if((CURL_EASY_STR(data, STRING_USERNAME) ||
C3: OPTION credential branch (lines 1428-1452) checks Curl_auth_allowed_to_origin before creating creds
1429 CURL_EASY_STR(data, STRING_PASSWORD) ||
1430 CURL_EASY_STR(data, STRING_BEARER) ||
1431 CURL_EASY_STR(data, STRING_SASL_AUTHZID) ||
1432 CURL_EASY_STR(data, STRING_SERVICE_NAME)) &&
1433 Curl_auth_allowed_to_origin(data, data->state.origin)) {
1434 result = Curl_creds_create(CURL_EASY_STR(data, STRING_USERNAME),
1435 CURL_EASY_STR(data, STRING_PASSWORD),
1436 CURL_EASY_STR(data, STRING_BEARER),
1437 CURL_EASY_STR(data, STRING_SASL_AUTHZID),
1438 CURL_EASY_STR(data, STRING_SERVICE_NAME),
1439 CREDS_OPTION, &newcreds);
1440 if(result)
1441 goto out;
1442 if(newcreds &&
1443 !(data->state.origin->scheme->flags & PROTOPT_USERPWDCTRL) &&
1444 (str_has_ctrl(Curl_creds_user(newcreds)) ||
1445 str_has_ctrl(Curl_creds_passwd(newcreds)))) {
1446 /* if the protocol cannot handle control codes in credentials, make
1447 sure there are none */
1448 failf(data, "control code detected in credentials");
1449 result = CURLE_BAD_FUNCTION_ARGUMENT;
1450 goto out;
1451 }
1452 }
1453
1454 /* Extract credentials from the URL only if there are none OR
1455 * if no CURLOPT_USER was set. */
1456 if(!newcreds || !Curl_creds_has_user(newcreds)) {
C3: URL credential branch (lines 1456-1495) has NO origin check - only condition is !newcreds || !Curl_creds_has_user(newcreds)
C5: URL credential branch populates data->state.creds from redirect Location header userinfo
1457 char *user = NULL;
1458 char *passwd = NULL;
1459 char *udecoded = NULL;
1460 char *pdecoded = NULL;
1461 CURLUcode uc;
1462
1463 uc = curl_url_get(uh, CURLUPART_USER, &user, 0);
1464 if(uc && (uc != CURLUE_NO_USER))
1465 result = Curl_uc_to_curlcode(uc);
1466 if(!result) {
1467 uc = curl_url_get(uh, CURLUPART_PASSWORD, &passwd, 0);
1468 if(uc && (uc != CURLUE_NO_PASSWORD))
1469 result = Curl_uc_to_curlcode(uc);
1470 }
1471 if(!result && user) {
1472 result = Curl_urldecode(user, 0, &udecoded, NULL,
1473 (data->state.origin->scheme->flags &
1474 PROTOPT_USERPWDCTRL) ?
1475 REJECT_ZERO : REJECT_CTRL);
1476 }
1477 if(!result && passwd) {
1478 result = Curl_urldecode(passwd, 0, &pdecoded, NULL,
1479 (data->state.origin->scheme->flags &
1480 PROTOPT_USERPWDCTRL) ?
1481 REJECT_ZERO : REJECT_CTRL);
1482 }
1483 if(!result)
1484 result = Curl_creds_merge(udecoded, pdecoded, newcreds,
1485 CREDS_URL, &newcreds);
1486
1487 curlx_free(udecoded);
1488 curlx_free(pdecoded);
1489 curlx_free(passwd);
1490 curlx_free(user);
1491 if(result) {
1492 failf(data, "error extracting credentials from URL");
1493 goto out;
1494 }
1495 }
1496
1497#ifndef CURL_DISABLE_NETRC
1498 /* Check for overridden login details and set them accordingly so that
1499 they are known when protocol->setup_connection is called! */
1500 result = url_set_data_creds_netrc(data, &newcreds);
1501#endif /* CURL_DISABLE_NETRC */
1502
1503out:
1504 if(!result && !Curl_creds_equal(data->state.creds, newcreds)) {
1505 /* Do we have more things to trigger on credentials change? */
1506 Curl_creds_link(&data->state.creds, newcreds);
1507 }
1508 Curl_creds_unlink(&newcreds);
1509 return result;
1510}
lib/http_negotiate.clines 155–264 · lines 219-219 cited by the report; definition of Curl_output_negotiate
155CURLcode Curl_output_negotiate(struct Curl_easy *data,
156 struct connectdata *conn, bool proxy)
157{
158 struct negotiatedata *neg_ctx;
159 struct auth *authp;
160 curlnegotiate *state;
161 char *base64 = NULL;
162 size_t len = 0;
163 char *userp;
164 CURLcode result;
165
166 if(proxy) {
167#ifndef CURL_DISABLE_PROXY
168 authp = &data->state.authproxy;
169 state = &conn->proxy_negotiate_state;
170#else
171 return CURLE_NOT_BUILT_IN;
172#endif
173 }
174 else {
175 authp = &data->state.authhost;
176 state = &conn->http_negotiate_state;
177 }
178 neg_ctx = Curl_auth_nego_get(conn, proxy);
179 if(!neg_ctx)
180 return CURLE_OUT_OF_MEMORY;
181
182 authp->done = FALSE;
183
184 if(*state == GSS_AUTHRECV) {
185 if(neg_ctx->havenegdata) {
186 neg_ctx->havemultiplerequests = TRUE;
187 }
188 }
189 else if(*state == GSS_AUTHSUCC) {
190 if(!neg_ctx->havenoauthpersist) {
191 neg_ctx->noauthpersist = !neg_ctx->havemultiplerequests;
192 }
193 }
194
195 if(neg_ctx->noauthpersist ||
196 (*state != GSS_AUTHDONE && *state != GSS_AUTHSUCC)) {
197
198 if(neg_ctx->noauthpersist && *state == GSS_AUTHSUCC) {
199 infof(data, "Curl_output_negotiate, "
200 "no persistent authentication: cleanup existing context");
201 http_auth_nego_reset(conn, neg_ctx, proxy);
202 }
203 if(!neg_ctx->context) {
204 result = Curl_input_negotiate(data, conn, proxy, "Negotiate");
205 if(result == CURLE_AUTH_ERROR) {
206 /* negotiate auth failed, let's continue unauthenticated to stay
207 * compatible with the behavior before curl-7_64_0-158-g6c6035532 */
208 authp->done = TRUE;
209 return CURLE_OK;
210 }
211 else if(result)
212 return result;
213 }
214
215 result = Curl_auth_create_spnego_message(neg_ctx, &base64, &len);
C4: Curl_auth_create_spnego_message mints token from client's Kerberos TGT, not from URL credentials
216 if(result)
217 return result;
218
219 userp = curl_maprintf("%sAuthorization: Negotiate %s\r\n",
C4: Authorization: Negotiate header constructed with the minted token
220 proxy ? "Proxy-" : "", base64);
221
222 if(proxy) {
223#ifndef CURL_DISABLE_PROXY
224 curlx_free(data->req.hd_proxy_auth);
225 data->req.hd_proxy_auth = userp;
226#endif
227 }
228 else {
229 curlx_free(data->req.hd_auth);
230 data->req.hd_auth = userp;
231 }
232
233 curlx_free(base64);
234
235 if(!userp) {
236 return CURLE_OUT_OF_MEMORY;
237 }
238
239 *state = GSS_AUTHSENT;
240#ifdef HAVE_GSSAPI
241 if(neg_ctx->status == GSS_S_COMPLETE ||
242 neg_ctx->status == GSS_S_CONTINUE_NEEDED) {
243 *state = GSS_AUTHDONE;
244 }
245#else
246#ifdef USE_WINDOWS_SSPI
247 if(neg_ctx->status == SEC_E_OK ||
248 neg_ctx->status == SEC_I_CONTINUE_NEEDED) {
249 *state = GSS_AUTHDONE;
250 }
251#endif
252#endif
253 }
254
255 if(*state == GSS_AUTHDONE || *state == GSS_AUTHSUCC) {
256 /* connection is already authenticated,
257 * do not send a header in future requests */
258 authp->done = TRUE;
259 }
260
261 neg_ctx->havenegdata = FALSE;
262
263 return CURLE_OK;
264}
lib/http.clines 646–796 · definition of output_auth_headers
646static 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);
C4: Curl_output_negotiate called when Negotiate auth is picked and no Authorization header present
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) {
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 &&
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}
include/curl/curl.hlines 850–852 · definition of CURLAUTH_ANY
Show 3 lines (not cited by the judge)
850#define CURLAUTH_ANY ((~(CURLAUTH_DIGEST_IE | \
851 CURLAUTH_HTTPSIG)) & \
852 ((unsigned long)0xffffffff))
include/curl/curl.hlines 835–835 · definition of CURLAUTH_NEGOTIATE
Show 1 lines (not cited by the judge)
835#define CURLAUTH_NEGOTIATE (((unsigned long)1) << 2)
lib/urldata.hlines 1228–1229 · definition of CURL_EASY_STR
Show 2 lines (not cited by the judge)
1228#define CURL_EASY_STR(d, id) \
1229 Curl_u8_strset_get(&(d)->set.strings, (uint8_t)(id))
lib/creds.clines 34–102 · definition of Curl_creds_create
Show 69 lines (not cited by the judge)
34CURLcode Curl_creds_create(const char *user,
35 const char *passwd,
36 const char *oauth_bearer,
37 const char *sasl_authzid,
38 const char *sasl_service,
39 uint8_t source,
40 struct Curl_creds **pcreds)
41{
42 struct Curl_creds *creds = NULL;
43 size_t ulen = user ? strlen(user) : 0;
44 size_t plen = passwd ? strlen(passwd) : 0;
45 size_t olen = oauth_bearer ? strlen(oauth_bearer) : 0;
46 size_t salen = sasl_authzid ? strlen(sasl_authzid) : 0;
47 size_t sslen = sasl_service ? strlen(sasl_service) : 0;
48 char *s, *buf;
49 size_t bufsize;
50 CURLcode result = CURLE_OK;
51
52 Curl_creds_unlink(pcreds);
53
54 /* Everything empty/NULL, this is the NULL credential */
55 if(!user && !passwd && !olen && !salen && !sslen)
56 goto out;
57
58 if((ulen > CURL_MAX_INPUT_LENGTH) ||
59 (plen > CURL_MAX_INPUT_LENGTH) ||
60 (olen > CURL_MAX_INPUT_LENGTH) ||
61 (salen > CURL_MAX_INPUT_LENGTH) ||
62 (sslen > CURL_MAX_INPUT_LENGTH)) {
63 result = CURLE_BAD_FUNCTION_ARGUMENT;
64 goto out;
65 }
66
67 /* null-terminator for user already part of struct */
68 bufsize = ulen + plen + 1 + olen + 1 + salen + 1 + sslen + 1;
69 creds = curlx_calloc(1, sizeof(*creds) + bufsize);
70 if(!creds) {
71 result = CURLE_OUT_OF_MEMORY;
72 goto out;
73 }
74
75 creds->bufsize = bufsize;
76 creds->refcount = 1;
77 creds->source = source;
78 /* Some compilers try to be too smart about our dynamic struct size */
79 buf = ((char *)creds) + offsetof(struct Curl_creds, buf);
80 creds->user = s = buf;
81 if(ulen)
82 memcpy(s, user, ulen + 1);
83 creds->passwd = s = buf + ulen + 1;
84 if(plen)
85 memcpy(s, passwd, plen + 1);
86 creds->oauth_bearer = s = buf + ulen + 1 + plen + 1;
87 if(olen)
88 memcpy(s, oauth_bearer, olen + 1);
89 creds->sasl_authzid = s = buf + ulen + 1 + plen + 1 + olen + 1;
90 if(salen)
91 memcpy(s, sasl_authzid, salen + 1);
92 creds->sasl_service = s = buf + ulen + 1 + plen + 1 + olen + 1 + salen + 1;
93 if(sslen)
94 memcpy(s, sasl_service, sslen + 1);
95
96out:
97 if(!result)
98 *pcreds = creds;
99 else
100 Curl_creds_unlink(&creds);
101 return result;
102}
lib/creds.hlines 75–75 · definition of Curl_creds_has_user
Show 1 lines (not cited by the judge)
75#define Curl_creds_has_user(c) ((c) && (c)->user[0])
lib/creds.clines 104–128 · definition of Curl_creds_merge
Show 25 lines (not cited by the judge)
104CURLcode Curl_creds_merge(const char *user,
105 const char *passwd,
106 struct Curl_creds *creds_in,
107 uint8_t source,
108 struct Curl_creds **pcreds_out)
109{
110 struct Curl_creds *creds_out = NULL;
111 CURLcode result;
112
113 if(!creds_in) {
114 result = Curl_creds_create(user, passwd, NULL, NULL, NULL,
115 source, &creds_out);
116 }
117 else {
118 result = Curl_creds_create(user ? user : Curl_creds_user(creds_in),
119 passwd ? passwd : Curl_creds_passwd(creds_in),
120 Curl_creds_oauth_bearer(creds_in),
121 Curl_creds_sasl_authzid(creds_in),
122 Curl_creds_sasl_service(creds_in),
123 source, &creds_out);
124 }
125 Curl_creds_link(pcreds_out, creds_out);
126 Curl_creds_unlink(&creds_out);
127 return result;
128}
lib/peer.clines 321–327 · definition of Curl_peer_equal
Show 7 lines (not cited by the judge)
321bool Curl_peer_equal(struct Curl_peer *p1, struct Curl_peer *p2)
322{
323 return (p1 == p2) ||
324 (p1 && p2 &&
325 (p1->scheme == p2->scheme) &&
326 Curl_peer_same_destination(p1, p2));
327}
lib/curl_setup.hlines 1048–1048 · definition of FALSE
Show 1 lines (not cited by the judge)
1048#define FALSE false
src/curlinfo.clines 273–281 · definition of main
Show 9 lines (not cited by the judge)
273int 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}