Commit 15f76bf7 authored by Jonathan Nieder's avatar Jonathan Nieder Committed by Daniel Stenberg
Browse files

Curl_setopt: handle arbitrary-length username and password

libcurl truncates usernames, passwords, and options set with
curl_easy_setopt to 255 (= MAX_CURL_PASSWORD_LENGTH - 1) characters.
This doesn't affect the return value from curl_easy_setopt(), so from
the caller's point of view, there is no sign anything strange has
happened, except that authentication fails.

For example:

  # Prepare a long (300-char) password.
  s=0123456789; s=$s$s$s$s$s$s$s$s$s$s; s=$s$s$s;
  # Start a server.
  nc -l -p 8888 | tee out & pid=$!
  # Tell curl to pass the password to the server.
  curl --user me:$s http://localhost:8888 & sleep 1; kill $pid
  # Extract the password.
  userpass=$(
	awk '/Authorization: Basic/ {print $3}' <out |
	tr -d '\r' |
	base64 -d
  )
  password=${userpass#me:}
  echo ${#password}

Expected result: 300
Actual result: 255

The fix is simple: allocate appropriately sized buffers on the heap
instead of trying to squeeze the provided values into fixed-size
on-stack buffers.

Bug: http://bugs.debian.org/719856
Reported-by: Colby Ranger
parent 36585b53
Loading
Loading
Loading
Loading
+19 −10
Original line number Diff line number Diff line
@@ -4793,23 +4793,29 @@ static CURLcode parse_remote_port(struct SessionHandle *data,
 * Override the login details from the URL with that in the CURLOPT_USERPWD
 * option or a .netrc file, if applicable.
 */
static void override_login(struct SessionHandle *data,
static int override_login(struct SessionHandle *data,
                          struct connectdata *conn,
                          char **userp, char **passwdp, char **optionsp)
{
  if(data->set.str[STRING_USERNAME]) {
    strncpy(*userp, data->set.str[STRING_USERNAME], MAX_CURL_USER_LENGTH);
    (*userp)[MAX_CURL_USER_LENGTH - 1] = '\0';   /* To be on safe side */
    free(*userp);
    *userp = strdup(data->set.str[STRING_USERNAME]);
    if(!*userp)
      return CURLE_OUT_OF_MEMORY;
  }

  if(data->set.str[STRING_PASSWORD]) {
    strncpy(*passwdp, data->set.str[STRING_PASSWORD], MAX_CURL_PASSWORD_LENGTH);
    (*passwdp)[MAX_CURL_PASSWORD_LENGTH - 1] = '\0'; /* To be on safe side */
    free(*passwdp);
    *passwdp = strdup(data->set.str[STRING_PASSWORD]);
    if(!*passwdp)
      return CURLE_OUT_OF_MEMORY;
  }

  if(data->set.str[STRING_OPTIONS]) {
    strncpy(*optionsp, data->set.str[STRING_OPTIONS], MAX_CURL_OPTIONS_LENGTH);
    (*optionsp)[MAX_CURL_OPTIONS_LENGTH - 1] = '\0'; /* To be on safe side */
    free(*optionsp);
    *optionsp = strdup(data->set.str[STRING_OPTIONS]);
    if(!*optionsp)
      return CURLE_OUT_OF_MEMORY;
  }

  conn->bits.netrc = FALSE;
@@ -4830,6 +4836,7 @@ static void override_login(struct SessionHandle *data,
      conn->bits.user_passwd = TRUE; /* enable user+password */
    }
  }
  return CURLE_OK;
}

/*
@@ -5278,7 +5285,9 @@ static CURLcode create_conn(struct SessionHandle *data,

  /* Check for overridden login details and set them accordingly so they
     they are known when protocol->setup_connection is called! */
  override_login(data, conn, &user, &passwd, &options);
  result = override_login(data, conn, &user, &passwd, &options);
  if(result != CURLE_OK)
    goto out;
  result = set_login(conn, user, passwd, options);
  if(result != CURLE_OK)
    goto out;