]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
http: clear credentials better on redirect
authorDaniel Stenberg <daniel@haxx.se>
Thu, 16 Apr 2026 12:26:20 +0000 (14:26 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 16 Apr 2026 19:51:41 +0000 (21:51 +0200)
Verify with test 2506: netrc with redirect using proxy

Updated test 998 which was wrong.

Reported-by: Muhamad Arga Reksapati
Closes #21345

lib/http.c
tests/data/Makefile.am
tests/data/test2506 [new file with mode: 0644]
tests/data/test998
tests/libtest/Makefile.inc
tests/libtest/lib2506.c [new file with mode: 0644]

index 34fa807d8d5769e8d36db963b86c6b101a5d6f8f..b6c1de0b6129a63b7e65d0364e71426d7bc58441 100644 (file)
@@ -1227,75 +1227,41 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl,
       return CURLE_OUT_OF_MEMORY;
   }
   else {
-    uc = curl_url_get(data->state.uh, CURLUPART_URL, &follow_url, 0);
-    if(uc)
+    bool same_origin;
+    CURLcode result;
+    CURLU *u = curl_url();
+    if(!u)
+      return CURLE_OUT_OF_MEMORY;
+    uc = curl_url_set(u, CURLUPART_URL,
+                      Curl_bufref_ptr(&data->state.url),
+                      CURLU_URLENCODE | CURLU_ALLOW_SPACE);
+    if(!uc)
+      uc = curl_url_get(data->state.uh, CURLUPART_URL, &follow_url, 0);
+    if(uc) {
+      curl_url_cleanup(u);
       return Curl_uc_to_curlcode(uc);
+    }
 
-    /* Clear auth if this redirects to a different port number or protocol,
-       unless permitted */
-    if(!data->set.allow_auth_to_other_hosts && (type != FOLLOW_FAKE)) {
-      uint16_t port;
-      bool clear = FALSE;
-
-      if(data->set.use_port && data->state.allow_port)
-        /* a custom port is used */
-        port = data->set.use_port;
-      else {
-        curl_off_t value;
-        char *portnum;
-        const char *p;
-        uc = curl_url_get(data->state.uh, CURLUPART_PORT, &portnum,
-                          CURLU_DEFAULT_PORT);
-        if(uc) {
-          curlx_free(follow_url);
-          return Curl_uc_to_curlcode(uc);
-        }
-        p = portnum;
-        curlx_str_number(&p, &value, 0xffff);
-        port = (uint16_t)value;
-        curlx_free(portnum);
-      }
-      if(port != data->info.conn_remote_port) {
-        infof(data, "Clear auth, redirects to port from %d to %d",
-              data->info.conn_remote_port, port);
-        clear = TRUE;
-      }
-      else {
-        char *scheme;
-        const struct Curl_scheme *p;
-        uc = curl_url_get(data->state.uh, CURLUPART_SCHEME, &scheme, 0);
-        if(uc) {
-          curlx_free(follow_url);
-          return Curl_uc_to_curlcode(uc);
-        }
+    same_origin = Curl_url_same_origin(u, data->state.uh);
+    curl_url_cleanup(u);
 
-        p = Curl_get_scheme(scheme);
-        if(p && (p->protocol != data->info.conn_protocol)) {
-          infof(data, "Clear auth, redirects scheme from %s to %s",
-                data->info.conn_scheme, scheme);
-          clear = TRUE;
-        }
-        curlx_free(scheme);
-      }
-      if(clear) {
-        CURLcode result = Curl_reset_userpwd(data);
-        if(result) {
-          curlx_free(follow_url);
-          return result;
-        }
-        curlx_safefree(data->state.aptr.user);
-        curlx_safefree(data->state.aptr.passwd);
+    if((!same_origin && !data->set.allow_auth_to_other_hosts) ||
+       !data->set.str[STRING_USERNAME]) {
+      result = Curl_reset_userpwd(data);
+      if(result) {
+        curlx_free(follow_url);
+        return result;
       }
+      curlx_safefree(data->state.aptr.user);
+      curlx_safefree(data->state.aptr.passwd);
     }
-  }
-  DEBUGASSERT(follow_url);
-  {
-    CURLcode result = Curl_reset_proxypwd(data);
+    result = Curl_reset_proxypwd(data);
     if(result) {
       curlx_free(follow_url);
       return result;
     }
   }
+  DEBUGASSERT(follow_url);
 
   if(type == FOLLOW_FAKE) {
     /* we are only figuring out the new URL if we would have followed locations
index 857389450ec2145820aa46d530b1bb74ba932ce6..e955c8383fbd27d1ad8d0fbcfd5f23be74418552 100644 (file)
@@ -265,7 +265,7 @@ test2309 \
 \
 test2400 test2401 test2402 test2403 test2404 test2405 test2406 test2407 \
 \
-test2500 test2501 test2502 test2503 test2504 test2505 \
+test2500 test2501 test2502 test2503 test2504 test2505 test2506 \
 \
 test2600 test2601 test2602 test2603 test2604 test2605 \
 \
diff --git a/tests/data/test2506 b/tests/data/test2506
new file mode 100644 (file)
index 0000000..9c65002
--- /dev/null
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="US-ASCII"?>
+<testcase>
+<info>
+<keywords>
+HTTP
+cookies
+</keywords>
+</info>
+
+<reply>
+<data crlf="headers" nocheck="yes">
+HTTP/1.1 301 redirect
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Content-Length: 3
+Location: http://numbertwo.example/%TESTNUMBER0002
+
+ok
+</data>
+<data2 crlf="headers" nocheck="yes">
+HTTP/1.1 200 OK
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Content-Length: 4
+
+yes
+</data2>
+</reply>
+
+<client>
+<server>
+http
+</server>
+<features>
+proxy
+</features>
+<tool>
+lib%TESTNUMBER
+</tool>
+<name>
+netrc with redirect using proxy
+</name>
+<file name="%LOGDIR/netrc2506">
+machine site.example login batman password robin
+</file>
+<command>
+http://%HOSTIP:%HTTPPORT http://site.example/ %LOGDIR/netrc2506
+</command>
+</client>
+
+<verify>
+<protocol crlf="headers">
+GET http://site.example/ HTTP/1.1
+Host: site.example
+Authorization: Basic %b64[batman:robin]b64%
+Accept: */*
+Proxy-Connection: Keep-Alive
+
+GET http://numbertwo.example/25060002 HTTP/1.1
+Host: numbertwo.example
+Accept: */*
+Proxy-Connection: Keep-Alive
+
+</protocol>
+</verify>
+</testcase>
index 24d1d3dd4e2b5bbb2eee49ecd486e67df41ac49b..56dbc0c89181d0c9b702f70b710f2ebd81a95535 100644 (file)
@@ -77,7 +77,6 @@ Proxy-Connection: Keep-Alive
 
 GET http://somewhere.else.example/a/path/9980002 HTTP/1.1
 Host: somewhere.else.example
-Authorization: Basic %b64[alberto:einstein]b64%
 User-Agent: curl/%VERSION
 Accept: */*
 Proxy-Connection: Keep-Alive
index bdf8a1dbea19916298187b643096fdbee6f37a52..10be282c178c5d7706279456f6736e94c84efa91 100644 (file)
@@ -112,7 +112,7 @@ TESTS_C = \
   lib2023.c lib2032.c lib2082.c \
   lib2301.c lib2302.c lib2304.c           lib2306.c lib2308.c lib2309.c \
   lib2402.c           lib2404.c lib2405.c \
-  lib2502.c lib2504.c lib2505.c \
+  lib2502.c lib2504.c lib2505.c lib2506.c \
   lib2700.c \
   lib3010.c lib3025.c lib3026.c lib3027.c lib3033.c lib3034.c \
   lib3100.c lib3101.c lib3102.c lib3103.c lib3104.c lib3105.c \
diff --git a/tests/libtest/lib2506.c b/tests/libtest/lib2506.c
new file mode 100644 (file)
index 0000000..8b3b342
--- /dev/null
@@ -0,0 +1,71 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Linus Nielsen Feltzing <linus@haxx.se>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "first.h"
+
+#include "testtrace.h"
+
+static size_t sink2506(char *ptr, size_t size, size_t nmemb, void *ud)
+{
+  (void)ptr;
+  (void)ud;
+  return size * nmemb;
+}
+
+static CURLcode test_lib2506(const char *URL)
+{
+  CURL *curl;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+
+  if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
+    curl_mfprintf(stderr, "curl_global_init() failed\n");
+    return TEST_ERR_MAJOR_BAD;
+  }
+
+  curl = curl_easy_init();
+  if(!curl) {
+    curl_mfprintf(stderr, "curl_easy_init() failed\n");
+    curl_global_cleanup();
+    return TEST_ERR_MAJOR_BAD;
+  }
+
+  test_setopt(curl, CURLOPT_WRITEFUNCTION, sink2506);
+  test_setopt(curl, CURLOPT_PROXY, URL);
+  test_setopt(curl, CURLOPT_URL, libtest_arg2);
+  test_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
+  test_setopt(curl, CURLOPT_NETRC_FILE, libtest_arg3);
+  test_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+  test_setopt(curl, CURLOPT_VERBOSE, 1L);
+
+  /* CURLOPT_UNRESTRICTED_AUTH should not make a difference because the
+     credentials come from netrc */
+  test_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, 1L);
+
+  result = curl_easy_perform(curl);
+
+test_cleanup:
+  curl_easy_cleanup(curl);
+  curl_global_cleanup();
+
+  return result;
+}