File curl-CVE-2024-11053.patch of Package curl.37295

From e9b9bbac22c26cf67316fa8e6c6b9e831af31949 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Fri, 15 Nov 2024 11:06:36 +0100
Subject: [PATCH] netrc: address several netrc parser flaws

- make sure that a match that returns a username also returns a
  password, that should be blank if no password is found

- fix handling of multiple logins for same host where the password/login
  order might be reversed.

- reject credentials provided in the .netrc if they contain ASCII control
  codes - if the used protocol does not support such (like HTTP and WS do)

Reported-by: Harry Sintonen

Add test 478, 479 and 480 to verify. Updated unit 1304.

Closes #15586
---
 lib/netrc.c            | 113 +++++++++++++++++++++++------------------
 lib/url.c              |  60 +++++++++++++++-------
 tests/data/Makefile.am |   2 +-
 tests/data/test478     |  73 ++++++++++++++++++++++++++
 tests/data/test479     | 107 ++++++++++++++++++++++++++++++++++++++
 tests/data/test480     |  38 ++++++++++++++
 tests/unit/unit1304.c  |  75 ++++++++-------------------
 7 files changed, 345 insertions(+), 123 deletions(-)
 create mode 100644 tests/data/test478
 create mode 100644 tests/data/test479
 create mode 100644 tests/data/test480

Index: curl-8.6.0/lib/netrc.c
===================================================================
--- curl-8.6.0.orig/lib/netrc.c
+++ curl-8.6.0/lib/netrc.c
@@ -238,6 +238,16 @@ static int parsenetrc(const char *host,
             state = HOSTFOUND;
             state_our_login = FALSE;
           }
+          else if(strcasecompare("default", tok)) {
+            state = HOSTVALID;
+            retcode = NETRC_SUCCESS; /* we did find our host */
+            Curl_safefree(password);
+            if(!specific_login)
+              if(login_alloc) {
+                free(login);
+                login_alloc = FALSE;
+              }
+          }
           break;
         } /* switch (state) */
         tok = ++tok_end;
@@ -245,6 +255,12 @@ static int parsenetrc(const char *host,
     } /* while Curl_get_line() */
 
 out:
+    if(!retcode && !password && state_our_login) {
+      /* success without a password, set a blank one */
+      password = strdup("");
+      if(!password)
+        retcode = 1; /* out of memory */
+    }
     if(!retcode) {
       /* success */
       if(login_alloc) {
Index: curl-8.6.0/lib/url.c
===================================================================
--- curl-8.6.0.orig/lib/url.c
+++ curl-8.6.0/lib/url.c
@@ -2725,6 +2725,17 @@ static CURLcode parse_remote_port(struct
   return CURLE_OK;
 }
 
+static bool str_has_ctrl(const char *input)
+{
+  const unsigned char *str = (const unsigned char *)input;
+  while(*str) {
+    if(*str < 0x20)
+      return TRUE;
+    str++;
+  }
+  return FALSE;
+}
+
 /*
  * Override the login details from the URL with that in the CURLOPT_USERPWD
  * option or a .netrc file, if applicable.
@@ -2755,29 +2766,40 @@ static CURLcode override_login(struct Cu
     bool url_provided = FALSE;
 
     if(data->state.aptr.user) {
-      /* there was a user name in the URL. Use the URL decoded version */
+      /* there was a username with a length in the URL. Use the URL decoded
+         version */
       userp = &data->state.aptr.user;
       url_provided = TRUE;
     }
 
-    ret = Curl_parsenetrc(conn->host.name,
-                          userp, passwdp,
-                          data->set.str[STRING_NETRC_FILE]);
-    if(ret > 0) {
-      infof(data, "Couldn't find host %s in the %s file; using defaults",
-            conn->host.name,
-            (data->set.str[STRING_NETRC_FILE] ?
-             data->set.str[STRING_NETRC_FILE] : ".netrc"));
-    }
-    else if(ret < 0) {
-      failf(data, ".netrc parser error");
-      return CURLE_READ_ERROR;
-    }
-    else {
-      /* set bits.netrc TRUE to remember that we got the name from a .netrc
-         file, so that it is safe to use even if we followed a Location: to a
-         different host or similar. */
-      conn->bits.netrc = TRUE;
+    if(!*passwdp) {
+      ret = Curl_parsenetrc(conn->host.name,
+                            userp, passwdp,
+                            data->set.str[STRING_NETRC_FILE]);
+      if(ret > 0) {
+        infof(data, "Couldn't find host %s in the %s file; using defaults",
+              conn->host.name,
+              (data->set.str[STRING_NETRC_FILE] ?
+               data->set.str[STRING_NETRC_FILE] : ".netrc"));
+      }
+      else if(ret < 0) {
+        failf(data, ".netrc parser error");
+        return CURLE_READ_ERROR;
+      }
+      else {
+        if(!(conn->handler->flags&PROTOPT_USERPWDCTRL)) {
+          /* if the protocol can't handle control codes in credentials, make
+             sure there are none */
+          if(str_has_ctrl(*userp) || str_has_ctrl(*passwdp)) {
+            failf(data, "control code detected in .netrc credentials");
+            return CURLE_READ_ERROR;
+          }
+        }
+        /* set bits.netrc TRUE to remember that we got the name from a .netrc
+           file, so that it is safe to use even if we followed a Location: to a
+           different host or similar. */
+        conn->bits.netrc = TRUE;
+      }
     }
     if(url_provided) {
       Curl_safefree(conn->user);
openSUSE Build Service is sponsored by