Blob Blame History Raw
From 965f26c806a87fbf9ae803d12d57b1e5f91e0754 Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Sat, 13 Apr 2013 10:49:42 +0100
Subject: [PATCH 01/28] url: Added support for parsing login options from the
 URL

As well as parsing the username and password from the URL, added support
for parsing the optional options part from the login details, to allow
the following supported URL format:

schema://username:password;options@example.com/path?q=foobar

This will only be used by IMAP, POP3 and SMTP at present but any
protocol that may be given login options in the URL will be able to
add support for them.

Upstream-commit: 73aa95592f47d461f0246eef1187f5d569aa6afa
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c     | 79 ++++++++++++++++++++++++++++++++++++++++++++---------------
 lib/urldata.h |  3 +++
 2 files changed, 62 insertions(+), 20 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index 2dc56ae..fdf6bca 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -2461,6 +2461,7 @@ static void conn_free(struct connectdata *conn)
 
   Curl_safefree(conn->user);
   Curl_safefree(conn->passwd);
+  Curl_safefree(conn->options);
   Curl_safefree(conn->proxyuser);
   Curl_safefree(conn->proxypasswd);
   Curl_safefree(conn->allocptr.proxyuserpwd);
@@ -4283,24 +4284,27 @@ static CURLcode parse_url_userpass(struct SessionHandle *data,
                                    struct connectdata *conn,
                                    char *user, char *passwd)
 {
+  char options[MAX_CURL_OPTIONS_LENGTH];
+
   /* At this point, we're hoping all the other special cases have
    * been taken care of, so conn->host.name is at most
-   *    [user[:password]]@]hostname
+   *    [user[:password][;options]]@]hostname
    *
    * We need somewhere to put the embedded details, so do that first.
    */
 
-  char *ptr=strchr(conn->host.name, '@');
+  char *ptr = strchr(conn->host.name, '@');
   char *userpass = conn->host.name;
 
-  user[0] =0;   /* to make everything well-defined */
-  passwd[0]=0;
+  user[0] = 0;   /* to make everything well-defined */
+  passwd[0] = 0;
+  options[0] = 0;
 
   /* We will now try to extract the
-   * possible user+password pair in a string like:
+   * possible login information in a string like:
    * ftp://user:password@ftp.my.site:8021/README */
   if(ptr != NULL) {
-    /* there's a user+password given here, to the left of the @ */
+    /* There's login information to the left of the @ */
 
     conn->host.name = ++ptr;
 
@@ -4310,26 +4314,46 @@ static CURLcode parse_url_userpass(struct SessionHandle *data,
      * set user/passwd, but doing that first adds more cases here :-(
      */
 
-    conn->bits.userpwd_in_url = TRUE;
     if(data->set.use_netrc != CURL_NETRC_REQUIRED) {
-      /* We could use the one in the URL */
-
-      conn->bits.user_passwd = TRUE; /* enable user+password */
-
+      /* We could use the information in the URL so extract it */
       if(*userpass != ':') {
-        /* the name is given, get user+password */
-        sscanf(userpass, "%" MAX_CURL_USER_LENGTH_TXT "[^:@]:"
-               "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]",
-               user, passwd);
+        if(*userpass != ';') {
+          /* The user is given so extract the user, password and options */
+          int result = sscanf(userpass,
+                              "%" MAX_CURL_USER_LENGTH_TXT "[^:;@]:"
+                              "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^;@];"
+                              "%" MAX_CURL_OPTIONS_LENGTH_TXT "[^@]",
+                              user, passwd, options);
+
+          /* The extract failed so extract the user and options instead */
+          if(result == 1)
+            sscanf(userpass, "%" MAX_CURL_USER_LENGTH_TXT "[^:;@];"
+                             "%" MAX_CURL_OPTIONS_LENGTH_TXT "[^@]",
+                              user, options);
+        }
+        else {
+          /* No name or password are given so extract the options only */
+        sscanf(userpass, ";%" MAX_CURL_OPTIONS_LENGTH_TXT "[^@]", options);
+        }
       }
       else
-        /* no name given, get the password only */
-        sscanf(userpass, ":%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", passwd);
+        /* No name is given so extract the password and options */
+        sscanf(userpass, ":%" MAX_CURL_PASSWORD_LENGTH_TXT "[^;@];"
+               "%" MAX_CURL_OPTIONS_LENGTH_TXT "[^@]",
+               passwd, options);
 
       if(user[0]) {
-        char *newname=curl_easy_unescape(data, user, 0, NULL);
+        char *newname;
+
+        /* We have a user in the URL */
+        conn->bits.userpwd_in_url = TRUE;
+        conn->bits.user_passwd = TRUE; /* enable user+password */
+
+        /* Decode the user */
+        newname = curl_easy_unescape(data, user, 0, NULL);
         if(!newname)
           return CURLE_OUT_OF_MEMORY;
+
         if(strlen(newname) < MAX_CURL_USER_LENGTH)
           strcpy(user, newname);
 
@@ -4337,18 +4361,33 @@ static CURLcode parse_url_userpass(struct SessionHandle *data,
            the unconverted name, it'll be wrong but what the heck */
         free(newname);
       }
+
       if(passwd[0]) {
-        /* we have a password found in the URL, decode it! */
-        char *newpasswd=curl_easy_unescape(data, passwd, 0, NULL);
+        /* We have a password in the URL so decode it */
+        char *newpasswd = curl_easy_unescape(data, passwd, 0, NULL);
         if(!newpasswd)
           return CURLE_OUT_OF_MEMORY;
+
         if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH)
           strcpy(passwd, newpasswd);
 
         free(newpasswd);
       }
+
+      if(options[0]) {
+        /* We have an options list in the URL so decode it */
+        char *newoptions = curl_easy_unescape(data, options, 0, NULL);
+        if(!newoptions)
+          return CURLE_OUT_OF_MEMORY;
+
+        if(strlen(newoptions) < MAX_CURL_OPTIONS_LENGTH)
+          conn->options = newoptions;
+        else
+          free(newoptions);
+      }
     }
   }
+
   return CURLE_OK;
 }
 
diff --git a/lib/urldata.h b/lib/urldata.h
index 26bc89f..46ef5d5 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -847,6 +847,7 @@ struct connectdata {
 
   char *user;    /* user name string, allocated */
   char *passwd;  /* password string, allocated */
+  char *options; /* options string, allocated */
 
   char *proxyuser;    /* proxy user name string, allocated */
   char *proxypasswd;  /* proxy password string, allocated */
@@ -1132,8 +1133,10 @@ typedef enum {
  * Session-data MUST be put in the connectdata struct and here.  */
 #define MAX_CURL_USER_LENGTH 256
 #define MAX_CURL_PASSWORD_LENGTH 256
+#define MAX_CURL_OPTIONS_LENGTH 256
 #define MAX_CURL_USER_LENGTH_TXT "255"
 #define MAX_CURL_PASSWORD_LENGTH_TXT "255"
+#define MAX_CURL_OPTIONS_LENGTH_TXT "255"
 
 struct auth {
   unsigned long want;  /* Bitmask set to the authentication methods wanted by
-- 
2.4.6


From 8e092594b858dd049e3f4f6660325f703e0a1c44 Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Thu, 18 Apr 2013 17:02:28 +0100
Subject: [PATCH 02/28] url: Reworked URL parsing to allow overriding by
 CURLOPT_USERPWD

Upstream-commit: 90c87f311eb087840008bfe89b19e6e0b808a246
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 50 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 31 insertions(+), 19 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index fdf6bca..4a9df84 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -140,7 +140,7 @@ static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke);
 static CURLcode do_init(struct connectdata *conn);
 static CURLcode parse_url_userpass(struct SessionHandle *data,
                                    struct connectdata *conn,
-                                   char *user, char *passwd);
+                                   char *user, char *passwd, char *options);
 /*
  * Protocol table.
  */
@@ -3585,8 +3585,7 @@ static CURLcode findprotocol(struct SessionHandle *data,
 static CURLcode parseurlandfillconn(struct SessionHandle *data,
                                     struct connectdata *conn,
                                     bool *prot_missing,
-                                    char *user,
-                                    char *passwd)
+                                    char *user, char *passwd, char *options)
 {
   char *at;
   char *fragment;
@@ -3811,7 +3810,7 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data,
    * Parse a user name and password in the URL and strip it out
    * of the host name
    *************************************************************/
-  result = parse_url_userpass(data, conn, user, passwd);
+  result = parse_url_userpass(data, conn, user, passwd, options);
   if(result != CURLE_OK)
     return result;
 
@@ -4282,10 +4281,8 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data,
  */
 static CURLcode parse_url_userpass(struct SessionHandle *data,
                                    struct connectdata *conn,
-                                   char *user, char *passwd)
+                                   char *user, char *passwd, char *options)
 {
-  char options[MAX_CURL_OPTIONS_LENGTH];
-
   /* At this point, we're hoping all the other special cases have
    * been taken care of, so conn->host.name is at most
    *    [user[:password][;options]]@]hostname
@@ -4381,9 +4378,9 @@ static CURLcode parse_url_userpass(struct SessionHandle *data,
           return CURLE_OUT_OF_MEMORY;
 
         if(strlen(newoptions) < MAX_CURL_OPTIONS_LENGTH)
-          conn->options = newoptions;
-        else
-          free(newoptions);
+          strcpy(options, newoptions);
+
+        free(newoptions);
       }
     }
   }
@@ -4551,11 +4548,13 @@ static void override_userpass(struct SessionHandle *data,
  * Set password so it's available in the connection.
  */
 static CURLcode set_userpass(struct connectdata *conn,
-                             const char *user, const char *passwd)
+                             const char *user, const char *passwd,
+                             const char *options)
 {
+  CURLcode result = CURLE_OK;
+
   /* If our protocol needs a password and we have none, use the defaults */
-  if((conn->handler->flags & PROTOPT_NEEDSPWD) &&
-     !conn->bits.user_passwd) {
+  if((conn->handler->flags & PROTOPT_NEEDSPWD) && !conn->bits.user_passwd) {
 
     conn->user = strdup(CURL_DEFAULT_USER);
     if(conn->user)
@@ -4565,17 +4564,28 @@ static CURLcode set_userpass(struct connectdata *conn,
     /* This is the default password, so DON'T set conn->bits.user_passwd */
   }
   else {
-    /* store user + password, zero-length if not set */
+    /* Store the user, zero-length if not set */
     conn->user = strdup(user);
+
+    /* Store the password (only if user is present), zero-length if not set */
     if(conn->user)
       conn->passwd = strdup(passwd);
     else
       conn->passwd = NULL;
   }
+
   if(!conn->user || !conn->passwd)
-    return CURLE_OUT_OF_MEMORY;
+    result = CURLE_OUT_OF_MEMORY;
 
-  return CURLE_OK;
+  /* Store the options, null if not set */
+  if(!result && options[0]) {
+    conn->options = strdup(options);
+
+    if(!conn->options)
+      result = CURLE_OUT_OF_MEMORY;
+  }
+
+  return result;
 }
 
 /*************************************************************
@@ -4745,12 +4755,13 @@ static CURLcode create_conn(struct SessionHandle *data,
                             struct connectdata **in_connect,
                             bool *async)
 {
-  CURLcode result=CURLE_OK;
+  CURLcode result = CURLE_OK;
   struct connectdata *conn;
   struct connectdata *conn_temp = NULL;
   size_t urllen;
   char user[MAX_CURL_USER_LENGTH];
   char passwd[MAX_CURL_PASSWORD_LENGTH];
+  char options[MAX_CURL_OPTIONS_LENGTH];
   bool reuse;
   char *proxy = NULL;
   bool prot_missing = FALSE;
@@ -4815,7 +4826,8 @@ static CURLcode create_conn(struct SessionHandle *data,
   conn->host.name = conn->host.rawalloc;
   conn->host.name[0] = 0;
 
-  result = parseurlandfillconn(data, conn, &prot_missing, user, passwd);
+  result = parseurlandfillconn(data, conn, &prot_missing, user, passwd,
+                               options);
   if(result != CURLE_OK)
     return result;
 
@@ -5016,7 +5028,7 @@ static CURLcode create_conn(struct SessionHandle *data,
    * for use
    *************************************************************/
   override_userpass(data, conn, user, passwd);
-  result = set_userpass(conn, user, passwd);
+  result = set_userpass(conn, user, passwd, options);
   if(result != CURLE_OK)
     return result;
 
-- 
2.4.6


From c9099e450c8eebbc3318f827a8532448f6a8631f Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Thu, 18 Apr 2013 17:09:40 +0100
Subject: [PATCH 03/28] url: Re-factored set_userpass() and
 parse_url_userpass()

Re-factored these functions to reflect their new behaviour following the
addition of login options.

Upstream-commit: 0d49e408a48246b9a27448473e78ce3fd237b19e
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 41 +++++++++++++++++++++++------------------
 1 file changed, 23 insertions(+), 18 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index 4a9df84..f03ca0f 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -138,9 +138,9 @@ find_oldest_idle_connection(struct SessionHandle *data);
 static void conn_free(struct connectdata *conn);
 static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke);
 static CURLcode do_init(struct connectdata *conn);
-static CURLcode parse_url_userpass(struct SessionHandle *data,
-                                   struct connectdata *conn,
-                                   char *user, char *passwd, char *options);
+static CURLcode parse_url_login(struct SessionHandle *data,
+                                struct connectdata *conn,
+                                char *user, char *passwd, char *options);
 /*
  * Protocol table.
  */
@@ -3806,11 +3806,11 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data,
     data->change.url_alloc = TRUE; /* free this later */
   }
 
-  /*************************************************************
-   * Parse a user name and password in the URL and strip it out
-   * of the host name
-   *************************************************************/
-  result = parse_url_userpass(data, conn, user, passwd, options);
+  /*
+   * Parse the login details from the URL and strip them out of
+   * the host name
+   */
+  result = parse_url_login(data, conn, user, passwd, options);
   if(result != CURLE_OK)
     return result;
 
@@ -4268,7 +4268,8 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data,
 
 /*
  *
- * Parse a user name and password in the URL and strip it out of the host name
+ * Parse the login details (user name, password and options) from the URL and
+ * strip them out of the host name
  *
  * Inputs: data->set.use_netrc (CURLOPT_NETRC)
  *         conn->host.name
@@ -4276,12 +4277,13 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data,
  * Outputs: (almost :- all currently undefined)
  *          conn->bits.user_passwd  - non-zero if non-default passwords exist
  *          user                    - non-zero length if defined
- *          passwd                  -   ditto
+ *          passwd                  - non-zero length if defined
+ *          options                 - non-zero length if defined
  *          conn->host.name         - remove user name and password
  */
-static CURLcode parse_url_userpass(struct SessionHandle *data,
-                                   struct connectdata *conn,
-                                   char *user, char *passwd, char *options)
+static CURLcode parse_url_login(struct SessionHandle *data,
+                                struct connectdata *conn,
+                                char *user, char *passwd, char *options)
 {
   /* At this point, we're hoping all the other special cases have
    * been taken care of, so conn->host.name is at most
@@ -4547,20 +4549,23 @@ static void override_userpass(struct SessionHandle *data,
 /*
  * Set password so it's available in the connection.
  */
-static CURLcode set_userpass(struct connectdata *conn,
-                             const char *user, const char *passwd,
-                             const char *options)
+static CURLcode set_login(struct connectdata *conn,
+                          const char *user, const char *passwd,
+                          const char *options)
 {
   CURLcode result = CURLE_OK;
 
   /* If our protocol needs a password and we have none, use the defaults */
   if((conn->handler->flags & PROTOPT_NEEDSPWD) && !conn->bits.user_passwd) {
-
+    /* Store the default user */
     conn->user = strdup(CURL_DEFAULT_USER);
+
+    /* Store the default password */
     if(conn->user)
       conn->passwd = strdup(CURL_DEFAULT_PASSWORD);
     else
       conn->passwd = NULL;
+
     /* This is the default password, so DON'T set conn->bits.user_passwd */
   }
   else {
@@ -5028,7 +5033,7 @@ static CURLcode create_conn(struct SessionHandle *data,
    * for use
    *************************************************************/
   override_userpass(data, conn, user, passwd);
-  result = set_userpass(conn, user, passwd, options);
+  result = set_login(conn, user, passwd, options);
   if(result != CURLE_OK)
     return result;
 
-- 
2.4.6


From a66a0feefcb037ffcfaf2dbd3dcd9f17a416ad13 Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Thu, 18 Apr 2013 17:52:05 +0100
Subject: [PATCH 04/28] url: Moved parsing of login details out of
 parse_url_login()

Separated the parsing of login details from the processing of them in
parse_url_login() ready for use by setstropt_userpwd().

Upstream-commit: bb20989a6384f95a73fd68b0e109fc860e0c7a57
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 221 +++++++++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 161 insertions(+), 60 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index f03ca0f..3396944 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -141,6 +141,9 @@ static CURLcode do_init(struct connectdata *conn);
 static CURLcode parse_url_login(struct SessionHandle *data,
                                 struct connectdata *conn,
                                 char *user, char *passwd, char *options);
+static CURLcode parse_login_details(const char *login, const size_t len,
+                                    char **userptr, char **passwdptr,
+                                    char **optionsptr);
 /*
  * Protocol table.
  */
@@ -4267,6 +4270,7 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data,
 #endif /* CURL_DISABLE_PROXY */
 
 /*
+ * parse_url_login()
  *
  * Parse the login details (user name, password and options) from the URL and
  * strip them out of the host name
@@ -4285,6 +4289,11 @@ static CURLcode parse_url_login(struct SessionHandle *data,
                                 struct connectdata *conn,
                                 char *user, char *passwd, char *options)
 {
+  CURLcode result = CURLE_OK;
+  char *userp = NULL;
+  char *passwdp = NULL;
+  char *optionsp = NULL;
+
   /* At this point, we're hoping all the other special cases have
    * been taken care of, so conn->host.name is at most
    *    [user[:password][;options]]@]hostname
@@ -4293,7 +4302,7 @@ static CURLcode parse_url_login(struct SessionHandle *data,
    */
 
   char *ptr = strchr(conn->host.name, '@');
-  char *userpass = conn->host.name;
+  char *login = conn->host.name;
 
   user[0] = 0;   /* to make everything well-defined */
   passwd[0] = 0;
@@ -4302,7 +4311,7 @@ static CURLcode parse_url_login(struct SessionHandle *data,
   /* We will now try to extract the
    * possible login information in a string like:
    * ftp://user:password@ftp.my.site:8021/README */
-  if(ptr != NULL) {
+  if(ptr) {
     /* There's login information to the left of the @ */
 
     conn->host.name = ++ptr;
@@ -4314,80 +4323,172 @@ static CURLcode parse_url_login(struct SessionHandle *data,
      */
 
     if(data->set.use_netrc != CURL_NETRC_REQUIRED) {
-      /* We could use the information in the URL so extract it */
-      if(*userpass != ':') {
-        if(*userpass != ';') {
-          /* The user is given so extract the user, password and options */
-          int result = sscanf(userpass,
-                              "%" MAX_CURL_USER_LENGTH_TXT "[^:;@]:"
-                              "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^;@];"
-                              "%" MAX_CURL_OPTIONS_LENGTH_TXT "[^@]",
-                              user, passwd, options);
-
-          /* The extract failed so extract the user and options instead */
-          if(result == 1)
-            sscanf(userpass, "%" MAX_CURL_USER_LENGTH_TXT "[^:;@];"
-                             "%" MAX_CURL_OPTIONS_LENGTH_TXT "[^@]",
-                              user, options);
-        }
-        else {
-          /* No name or password are given so extract the options only */
-        sscanf(userpass, ";%" MAX_CURL_OPTIONS_LENGTH_TXT "[^@]", options);
+      /* We could use the login information in the URL so extract it */
+      result = parse_login_details(login, ptr - login - 1,
+                                   &userp, &passwdp, &optionsp);
+      if(!result) {
+        if(userp) {
+          char *newname;
+
+          /* We have a user in the URL */
+          conn->bits.userpwd_in_url = TRUE;
+          conn->bits.user_passwd = TRUE; /* enable user+password */
+
+          /* Decode the user */
+          newname = curl_easy_unescape(data, userp, 0, NULL);
+          if(!newname)
+            return CURLE_OUT_OF_MEMORY;
+
+          if(strlen(newname) < MAX_CURL_USER_LENGTH)
+            strcpy(user, newname);
+
+          free(newname);
         }
-      }
-      else
-        /* No name is given so extract the password and options */
-        sscanf(userpass, ":%" MAX_CURL_PASSWORD_LENGTH_TXT "[^;@];"
-               "%" MAX_CURL_OPTIONS_LENGTH_TXT "[^@]",
-               passwd, options);
 
-      if(user[0]) {
-        char *newname;
+        if(passwdp) {
+          /* We have a password in the URL so decode it */
+          char *newpasswd = curl_easy_unescape(data, passwdp, 0, NULL);
+          if(!newpasswd)
+            return CURLE_OUT_OF_MEMORY;
 
-        /* We have a user in the URL */
-        conn->bits.userpwd_in_url = TRUE;
-        conn->bits.user_passwd = TRUE; /* enable user+password */
+          if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH)
+            strcpy(passwd, newpasswd);
 
-        /* Decode the user */
-        newname = curl_easy_unescape(data, user, 0, NULL);
-        if(!newname)
-          return CURLE_OUT_OF_MEMORY;
+          free(newpasswd);
+        }
+
+        if(optionsp) {
+          /* We have an options list in the URL so decode it */
+          char *newoptions = curl_easy_unescape(data, optionsp, 0, NULL);
+          if(!newoptions)
+            return CURLE_OUT_OF_MEMORY;
 
-        if(strlen(newname) < MAX_CURL_USER_LENGTH)
-          strcpy(user, newname);
+          if(strlen(newoptions) < MAX_CURL_OPTIONS_LENGTH)
+            strcpy(options, newoptions);
 
-        /* if the new name is longer than accepted, then just use
-           the unconverted name, it'll be wrong but what the heck */
-        free(newname);
+          free(newoptions);
+        }
       }
 
-      if(passwd[0]) {
-        /* We have a password in the URL so decode it */
-        char *newpasswd = curl_easy_unescape(data, passwd, 0, NULL);
-        if(!newpasswd)
-          return CURLE_OUT_OF_MEMORY;
+      Curl_safefree(userp);
+      Curl_safefree(passwdp);
+      Curl_safefree(optionsp);
+    }
+  }
 
-        if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH)
-          strcpy(passwd, newpasswd);
+  return result;
+}
 
-        free(newpasswd);
-      }
+/*
+ * parse_login_details()
+ *
+ * This is used to parse a login string for user name, password and options in
+ * the following formats:
+ *
+ *   user
+ *   user:password
+ *   user:password;options
+ *   user;options
+ *   user;options:password
+ *   :password
+ *   :password;options
+ *   ;options
+ *   ;options:password
+ *
+ * Parameters:
+ *
+ * login    [in]     - The login string.
+ * len      [in]     - The length of the login string.
+ * userp    [in/out] - The address where a pointer to newly allocated memory
+ *                     holding the user will be stored upon completion.
+ * passdwp  [in/out] - The address where a pointer to newly allocated memory
+ *                     holding the password will be stored upon completion.
+ * optionsp [in/out] - The address where a pointer to newly allocated memory
+ *                     holding the options will be stored upon completion.
+ *
+ * Returns CURLE_OK on success.
+ */
+static CURLcode parse_login_details(const char *login, const size_t len,
+                                    char **userp, char **passwdp,
+                                    char **optionsp)
+{
+  CURLcode result = CURLE_OK;
+  char *utemp = NULL;
+  char *ptemp = NULL;
+  char *otemp = NULL;
+  const char *psep = NULL;
+  const char *osep = NULL;
+  size_t ulen;
+  size_t plen;
+  size_t olen;
+
+  /* Attempt to find the password separator */
+  if(passwdp)
+    psep = strchr(login, ':');
+
+  /* Attempt to find the options separator */
+  if(optionsp)
+    osep = strchr(login, ';');
+
+  /* Calculate the portion lengths */
+  ulen = (psep ?
+          (size_t)(osep && psep > osep ? osep - login : psep - login) :
+          (osep ? (size_t)(osep - login) : len));
+  plen = (psep ?
+          (osep && osep > psep ? (size_t)(osep - psep) :
+                                 (size_t)(login + len - psep)) - 1 : 0);
+  olen = (osep ?
+          (psep && psep > osep ? (size_t)(psep - osep) :
+                                 (size_t)(login + len - osep)) - 1 : 0);
+
+  /* Allocate the user portion temporary buffer */
+  if(userp && ulen) {
+    utemp = malloc(ulen + 1);
+    if(!utemp)
+      result = CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Allocate the password portion temporary buffer */
+  if(!result && passwdp && plen) {
+    ptemp = malloc(plen + 1);
+    if(!ptemp)
+      result = CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Allocate the options  portion temporary buffer */
+  if(!result && optionsp && olen) {
+    otemp = malloc(olen + 1);
+    if(!otemp)
+      result = CURLE_OUT_OF_MEMORY;
+  }
 
-      if(options[0]) {
-        /* We have an options list in the URL so decode it */
-        char *newoptions = curl_easy_unescape(data, options, 0, NULL);
-        if(!newoptions)
-          return CURLE_OUT_OF_MEMORY;
+  if(!result) {
+    /* Copy the user portion if necessary */
+    if(utemp) {
+      memcpy(utemp, login, ulen);
+      utemp[ulen] = '\0';
+      Curl_safefree(*userp);
+      *userp = utemp;
+    }
 
-        if(strlen(newoptions) < MAX_CURL_OPTIONS_LENGTH)
-          strcpy(options, newoptions);
+    /* Copy the password portion if necessary */
+    if(ptemp) {
+      memcpy(ptemp, psep + 1, plen);
+      ptemp[plen] = '\0';
+      Curl_safefree(*passwdp);
+      *passwdp = ptemp;
+    }
 
-        free(newoptions);
-      }
+    /* Copy the options portion if necessary */
+    if(otemp) {
+      memcpy(otemp, osep + 1, olen);
+      otemp[olen] = '\0';
+      Curl_safefree(*optionsp);
+      *optionsp = otemp;
     }
   }
 
-  return CURLE_OK;
+  return result;
 }
 
 /*************************************************************
-- 
2.4.6


From ce1718fc19267ca33e61ac4bff2e3867d6ed460c Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Fri, 19 Apr 2013 19:37:55 +0100
Subject: [PATCH 05/28] url: Added bounds checking to parse_login_details()

Added bounds checking when searching for the separator characters within
the login string as this string may not be NULL terminated (For example
it is the login part of a URL). We do this in preference to allocating a
new string to copy the login details into which could then be passed to
parse_login_details() for performance reasons.

Upstream-commit: 49184c37233c2cf27b79ebcd29fb8a4f5fb2e1ed
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index 3396944..5381872 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -4423,13 +4423,23 @@ static CURLcode parse_login_details(const char *login, const size_t len,
   size_t olen;
 
   /* Attempt to find the password separator */
-  if(passwdp)
+  if(passwdp) {
     psep = strchr(login, ':');
 
+    /* Within the constraint of the login string */
+    if(psep >= login + len)
+      psep = NULL;
+  }
+
   /* Attempt to find the options separator */
-  if(optionsp)
+  if(optionsp) {
     osep = strchr(login, ';');
 
+    /* Within the constraint of the login string */
+    if(osep >= login + len)
+      osep = NULL;
+  }
+
   /* Calculate the portion lengths */
   ulen = (psep ?
           (size_t)(osep && psep > osep ? osep - login : psep - login) :
-- 
2.4.6


From fb76a0dac86f2b82f68b6b3b7538b5057d1c04d9 Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Sat, 20 Apr 2013 08:47:59 +0100
Subject: [PATCH 06/28] url: Added support for parsing login options from the
 CURLOPT_USERPWD

In addition to parsing the optional login options from the URL, added
support for parsing them from CURLOPT_USERPWD, to allow the following
supported command line:

--user username:password;options

Upstream-commit: fddb7b44a79d78e05043e1c97e069308b6b85f79
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c     | 66 ++++++++++++++++++++++++++++++++++-------------------------
 lib/urldata.h |  1 +
 2 files changed, 39 insertions(+), 28 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index 5381872..0a47143 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -295,43 +295,52 @@ static CURLcode setstropt(char **charp, char * s)
 }
 
 static CURLcode setstropt_userpwd(char *option, char **user_storage,
-                                  char **pwd_storage)
+                                  char **pwd_storage, char **options_storage)
 {
-  char* separator;
   CURLcode result = CURLE_OK;
+  char *userp = NULL;
+  char *passwdp = NULL;
+  char *optionsp = NULL;
 
   if(!option) {
     /* we treat a NULL passed in as a hint to clear existing info */
-    Curl_safefree(*user_storage);
-    *user_storage = (char *) NULL;
-    Curl_safefree(*pwd_storage);
-    *pwd_storage = (char *) NULL;
+    if(user_storage) {
+      Curl_safefree(*user_storage);
+      *user_storage = (char *) NULL;
+    }
+
+    if(pwd_storage) {
+      Curl_safefree(*pwd_storage);
+      *pwd_storage = (char *) NULL;
+    }
+
+    if(options_storage) {
+      Curl_safefree(*options_storage);
+      *options_storage = (char *) NULL;
+    }
+
     return CURLE_OK;
   }
 
-  separator = strchr(option, ':');
-  if(separator != NULL) {
-
+  /* Parse the login details */
+  result = parse_login_details(option, strlen(option),
+                               (user_storage ? &userp : NULL),
+                               (pwd_storage ? &passwdp : NULL),
+                               (options_storage ? &optionsp : NULL));
+  if(!result) {
     /* store username part of option */
-    char * p;
-    size_t username_len = (size_t)(separator-option);
-    p = malloc(username_len+1);
-    if(!p)
-      result = CURLE_OUT_OF_MEMORY;
-    else {
-      memcpy(p, option, username_len);
-      p[username_len] = '\0';
-      Curl_safefree(*user_storage);
-      *user_storage = p;
-    }
+    if(user_storage)
+      setstropt(user_storage, userp);
 
     /* store password part of option */
-    if(result == CURLE_OK)
-      result = setstropt(pwd_storage, separator+1);
-  }
-  else {
-    result = setstropt(user_storage, option);
+    if(pwd_storage)
+      setstropt(pwd_storage, passwdp);
+
+    /* store options part of option */
+    if(options_storage)
+      setstropt(options_storage, optionsp);
   }
+
   return result;
 }
 
@@ -1546,11 +1555,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
 
   case CURLOPT_USERPWD:
     /*
-     * user:password to use in the operation
+     * user:password;options to use in the operation
      */
     result = setstropt_userpwd(va_arg(param, char *),
                                &data->set.str[STRING_USERNAME],
-                               &data->set.str[STRING_PASSWORD]);
+                               &data->set.str[STRING_PASSWORD],
+                               &data->set.str[STRING_OPTIONS]);
     break;
   case CURLOPT_USERNAME:
     /*
@@ -1623,7 +1633,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      */
     result = setstropt_userpwd(va_arg(param, char *),
                                &data->set.str[STRING_PROXYUSERNAME],
-                               &data->set.str[STRING_PROXYPASSWORD]);
+                               &data->set.str[STRING_PROXYPASSWORD], NULL);
     break;
   case CURLOPT_PROXYUSERNAME:
     /*
diff --git a/lib/urldata.h b/lib/urldata.h
index 46ef5d5..1c2281a 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1354,6 +1354,7 @@ enum dupstring {
   STRING_SSL_ISSUERCERT,  /* issuer cert file to check certificate */
   STRING_USERNAME,        /* <username>, if used */
   STRING_PASSWORD,        /* <password>, if used */
+  STRING_OPTIONS,         /* <options>, if used */
   STRING_PROXYUSERNAME,   /* Proxy <username>, if used */
   STRING_PROXYPASSWORD,   /* Proxy <password>, if used */
   STRING_NOPROXY,         /* List of hosts which should not use the proxy, if
-- 
2.4.6


From 32f237261f2c7592db3ba6378c053e63abb744ce Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Sat, 20 Apr 2013 09:06:53 +0100
Subject: [PATCH 07/28] url: Added overriding of URL login options from
 CURLOPT_USERPWD

Upstream-commit: d535c4a2e1f78d4b54767d67e17cca805e2d1f7c
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 31 +++++++++++++++++--------------
 1 file changed, 17 insertions(+), 14 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index 0a47143..8b7aa3a 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -4631,20 +4631,26 @@ static CURLcode parse_remote_port(struct SessionHandle *data,
 }
 
 /*
- * Override a user name and password from the URL with that in the
- * CURLOPT_USERPWD option or a .netrc file, if applicable.
+ * Override the login details from the URL with that in the CURLOPT_USERPWD
+ * option or a .netrc file, if applicable.
  */
-static void override_userpass(struct SessionHandle *data,
-                              struct connectdata *conn,
-                              char *user, char *passwd)
+static void override_login(struct SessionHandle *data,
+                           struct connectdata *conn,
+                           char *user, char *passwd, char *options)
 {
-  if(data->set.str[STRING_USERNAME] != NULL) {
+  if(data->set.str[STRING_USERNAME]) {
     strncpy(user, data->set.str[STRING_USERNAME], MAX_CURL_USER_LENGTH);
-    user[MAX_CURL_USER_LENGTH-1] = '\0';   /*To be on safe side*/
+    user[MAX_CURL_USER_LENGTH - 1] = '\0';   /* To be on safe side */
   }
-  if(data->set.str[STRING_PASSWORD] != NULL) {
+
+  if(data->set.str[STRING_PASSWORD]) {
     strncpy(passwd, data->set.str[STRING_PASSWORD], MAX_CURL_PASSWORD_LENGTH);
-    passwd[MAX_CURL_PASSWORD_LENGTH-1] = '\0'; /*To be on safe side*/
+    passwd[MAX_CURL_PASSWORD_LENGTH - 1] = '\0'; /* To be on safe side */
+  }
+
+  if(data->set.str[STRING_OPTIONS]) {
+    strncpy(options, data->set.str[STRING_OPTIONS], MAX_CURL_OPTIONS_LENGTH);
+    options[MAX_CURL_OPTIONS_LENGTH - 1] = '\0'; /* To be on safe side */
   }
 
   conn->bits.netrc = FALSE;
@@ -5149,11 +5155,8 @@ static CURLcode create_conn(struct SessionHandle *data,
   if(result != CURLE_OK)
     return result;
 
-  /*************************************************************
-   * Check for an overridden user name and password, then set it
-   * for use
-   *************************************************************/
-  override_userpass(data, conn, user, passwd);
+  /* Check for overridden login details and set them accordingly */
+  override_login(data, conn, user, passwd, options);
   result = set_login(conn, user, passwd, options);
   if(result != CURLE_OK)
     return result;
-- 
2.4.6


From 4876aa898d1d0b012328c3ddc96fd2023464584e Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Sat, 20 Apr 2013 18:40:13 +0100
Subject: [PATCH 08/28] url: Fixed memory leak in setstropt_userpwd()

setstropt_userpwd() was calling setstropt() in commit fddb7b44a79d to
set each of the login details which would duplicate the strings and
subsequently cause a memory leak.

Upstream-commit: fe880475ed3c7e51e32e19112252c79e921cc31b
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index 8b7aa3a..5e27818 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -330,15 +330,18 @@ static CURLcode setstropt_userpwd(char *option, char **user_storage,
   if(!result) {
     /* store username part of option */
     if(user_storage)
-      setstropt(user_storage, userp);
+      Curl_safefree(*user_storage);
+      *user_storage = userp;
 
     /* store password part of option */
     if(pwd_storage)
-      setstropt(pwd_storage, passwdp);
+      Curl_safefree(*pwd_storage);
+      *pwd_storage = passwdp;
 
     /* store options part of option */
     if(options_storage)
-      setstropt(options_storage, optionsp);
+      Curl_safefree(*options_storage);
+      *options_storage = optionsp;
   }
 
   return result;
-- 
2.4.6


From d0d89877466515b3ec17bc7c5987f4fec906e92e Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Sat, 20 Apr 2013 19:10:10 +0100
Subject: [PATCH 09/28] url: Correction to scope of if statements when setting
 data

Upstream-commit: e99c81a07c0c8752a286e0f14174ae7ae114090c
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index 5e27818..ffd80a5 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -329,19 +329,22 @@ static CURLcode setstropt_userpwd(char *option, char **user_storage,
                                (options_storage ? &optionsp : NULL));
   if(!result) {
     /* store username part of option */
-    if(user_storage)
+    if(user_storage) {
       Curl_safefree(*user_storage);
       *user_storage = userp;
+    }
 
     /* store password part of option */
-    if(pwd_storage)
+    if(pwd_storage) {
       Curl_safefree(*pwd_storage);
       *pwd_storage = passwdp;
+    }
 
     /* store options part of option */
-    if(options_storage)
+    if(options_storage) {
       Curl_safefree(*options_storage);
       *options_storage = optionsp;
+    }
   }
 
   return result;
-- 
2.4.6


From f45b4761cdb3b88647aa4b7eee89bb45dfd7c7bc Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Sat, 20 Apr 2013 20:01:40 +0100
Subject: [PATCH 10/28] url: Simplified setstropt_userpwd() following recent
 changes

There is no need to perform separate clearing of data if a NULL option
pointer is passed in. Instead this operation can be performed by simply
not calling parse_login_details() and letting the rest of the code do
the work.

Upstream-commit: bddf3d4705ed8e0999200c92de191db8e2441b3a
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 30 +++++++-----------------------
 1 file changed, 7 insertions(+), 23 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index ffd80a5..5f1bef2 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -302,31 +302,15 @@ static CURLcode setstropt_userpwd(char *option, char **user_storage,
   char *passwdp = NULL;
   char *optionsp = NULL;
 
-  if(!option) {
-    /* we treat a NULL passed in as a hint to clear existing info */
-    if(user_storage) {
-      Curl_safefree(*user_storage);
-      *user_storage = (char *) NULL;
-    }
-
-    if(pwd_storage) {
-      Curl_safefree(*pwd_storage);
-      *pwd_storage = (char *) NULL;
-    }
-
-    if(options_storage) {
-      Curl_safefree(*options_storage);
-      *options_storage = (char *) NULL;
-    }
-
-    return CURLE_OK;
+  /* Parse the login details if specified. It not then we treat NULL as a hint
+     to clear the existing data */
+  if(option) {
+    result = parse_login_details(option, strlen(option),
+                                 (user_storage ? &userp : NULL),
+                                 (pwd_storage ? &passwdp : NULL),
+                                 (options_storage ? &optionsp : NULL));
   }
 
-  /* Parse the login details */
-  result = parse_login_details(option, strlen(option),
-                               (user_storage ? &userp : NULL),
-                               (pwd_storage ? &passwdp : NULL),
-                               (options_storage ? &optionsp : NULL));
   if(!result) {
     /* store username part of option */
     if(user_storage) {
-- 
2.4.6


From 34d2d13cdc6a50ea80c45366ea78487cca8f0fc4 Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Sun, 21 Apr 2013 10:08:17 +0100
Subject: [PATCH 11/28] url: Tidy up of code and comments following recent
 changes

Tidy up of variable names and comments in setstropt_userpwd() and
parse_login_details().

Upstream-commit: e8a9f794f048251f94d59cc1d4ef7e9516b0c4e7
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 84 +++++++++++++++++++++++++++++++--------------------------------
 1 file changed, 42 insertions(+), 42 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index 5f1bef2..5f9fd6f 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -261,7 +261,7 @@ static const struct Curl_handler Curl_handler_dummy = {
   PROTOPT_NONE                          /* flags */
 };
 
-void Curl_freeset(struct SessionHandle * data)
+void Curl_freeset(struct SessionHandle *data)
 {
   /* Free all dynamic strings stored in the data->set substructure. */
   enum dupstring i;
@@ -275,7 +275,7 @@ void Curl_freeset(struct SessionHandle * data)
   data->change.referer = NULL;
 }
 
-static CURLcode setstropt(char **charp, char * s)
+static CURLcode setstropt(char **charp, char *s)
 {
   /* Release the previous storage at `charp' and replace by a dynamic storage
      copy of `s'. Return CURLE_OK or CURLE_OUT_OF_MEMORY. */
@@ -298,43 +298,43 @@ static CURLcode setstropt_userpwd(char *option, char **user_storage,
                                   char **pwd_storage, char **options_storage)
 {
   CURLcode result = CURLE_OK;
-  char *userp = NULL;
-  char *passwdp = NULL;
-  char *optionsp = NULL;
+  char *user = NULL;
+  char *passwd = NULL;
+  char *options = NULL;
 
   /* Parse the login details if specified. It not then we treat NULL as a hint
      to clear the existing data */
   if(option) {
     result = parse_login_details(option, strlen(option),
-                                 (user_storage ? &userp : NULL),
-                                 (pwd_storage ? &passwdp : NULL),
-                                 (options_storage ? &optionsp : NULL));
+                                 (user_storage ? &user : NULL),
+                                 (pwd_storage ? &passwd : NULL),
+                                 (options_storage ? &options : NULL));
   }
 
   if(!result) {
-    /* store username part of option */
+    /* Store the username part of option if required */
     if(user_storage) {
       Curl_safefree(*user_storage);
-      *user_storage = userp;
+      *user_storage = user;
     }
 
-    /* store password part of option */
+    /* Store the password part of option if required */
     if(pwd_storage) {
       Curl_safefree(*pwd_storage);
-      *pwd_storage = passwdp;
+      *pwd_storage = passwd;
     }
 
-    /* store options part of option */
+    /* Store the options part of option if required */
     if(options_storage) {
       Curl_safefree(*options_storage);
-      *options_storage = optionsp;
+      *options_storage = options;
     }
   }
 
   return result;
 }
 
-CURLcode Curl_dupset(struct SessionHandle * dst, struct SessionHandle * src)
+CURLcode Curl_dupset(struct SessionHandle *dst, struct SessionHandle *src)
 {
   CURLcode r = CURLE_OK;
   enum dupstring i;
@@ -4413,9 +4413,9 @@ static CURLcode parse_login_details(const char *login, const size_t len,
                                     char **optionsp)
 {
   CURLcode result = CURLE_OK;
-  char *utemp = NULL;
-  char *ptemp = NULL;
-  char *otemp = NULL;
+  char *ubuf = NULL;
+  char *pbuf = NULL;
+  char *obuf = NULL;
   const char *psep = NULL;
   const char *osep = NULL;
   size_t ulen;
@@ -4451,50 +4451,50 @@ static CURLcode parse_login_details(const char *login, const size_t len,
           (psep && psep > osep ? (size_t)(psep - osep) :
                                  (size_t)(login + len - osep)) - 1 : 0);
 
-  /* Allocate the user portion temporary buffer */
+  /* Allocate the user portion buffer */
   if(userp && ulen) {
-    utemp = malloc(ulen + 1);
-    if(!utemp)
+    ubuf = malloc(ulen + 1);
+    if(!ubuf)
       result = CURLE_OUT_OF_MEMORY;
   }
 
-  /* Allocate the password portion temporary buffer */
+  /* Allocate the password portion buffer */
   if(!result && passwdp && plen) {
-    ptemp = malloc(plen + 1);
-    if(!ptemp)
+    pbuf = malloc(plen + 1);
+    if(!pbuf)
       result = CURLE_OUT_OF_MEMORY;
   }
 
-  /* Allocate the options  portion temporary buffer */
+  /* Allocate the options portion buffer */
   if(!result && optionsp && olen) {
-    otemp = malloc(olen + 1);
-    if(!otemp)
+    obuf = malloc(olen + 1);
+    if(!obuf)
       result = CURLE_OUT_OF_MEMORY;
   }
 
   if(!result) {
-    /* Copy the user portion if necessary */
-    if(utemp) {
-      memcpy(utemp, login, ulen);
-      utemp[ulen] = '\0';
+    /* Store the user portion if necessary */
+    if(ubuf) {
+      memcpy(ubuf, login, ulen);
+      ubuf[ulen] = '\0';
       Curl_safefree(*userp);
-      *userp = utemp;
+      *userp = ubuf;
     }
 
-    /* Copy the password portion if necessary */
-    if(ptemp) {
-      memcpy(ptemp, psep + 1, plen);
-      ptemp[plen] = '\0';
+    /* Store the password portion if necessary */
+    if(pbuf) {
+      memcpy(pbuf, psep + 1, plen);
+      pbuf[plen] = '\0';
       Curl_safefree(*passwdp);
-      *passwdp = ptemp;
+      *passwdp = pbuf;
     }
 
-    /* Copy the options portion if necessary */
-    if(otemp) {
-      memcpy(otemp, osep + 1, olen);
-      otemp[olen] = '\0';
+    /* Store the options portion if necessary */
+    if(obuf) {
+      memcpy(obuf, osep + 1, olen);
+      obuf[olen] = '\0';
       Curl_safefree(*optionsp);
-      *optionsp = otemp;
+      *optionsp = obuf;
     }
   }
 
-- 
2.4.6


From 58e3995c51150621185e9e0ebcbd943403a2df9c Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Sun, 21 Apr 2013 10:16:51 +0100
Subject: [PATCH 12/28] url: Tidy up of setstropt_userpwd() parameters

Updated the naming convention of the login parameters to match those of
other functions.

Upstream-commit: 702b0dd408d5e847aad99d44dcd79366c61835eb
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index 5f9fd6f..2e691c3 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -294,8 +294,8 @@ static CURLcode setstropt(char **charp, char *s)
   return CURLE_OK;
 }
 
-static CURLcode setstropt_userpwd(char *option, char **user_storage,
-                                  char **pwd_storage, char **options_storage)
+static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp,
+                                  char **optionsp)
 {
   CURLcode result = CURLE_OK;
   char *user = NULL;
@@ -306,28 +306,28 @@ static CURLcode setstropt_userpwd(char *option, char **user_storage,
      to clear the existing data */
   if(option) {
     result = parse_login_details(option, strlen(option),
-                                 (user_storage ? &user : NULL),
-                                 (pwd_storage ? &passwd : NULL),
-                                 (options_storage ? &options : NULL));
+                                 (userp ? &user : NULL),
+                                 (passwdp ? &passwd : NULL),
+                                 (optionsp ? &options : NULL));
   }
 
   if(!result) {
     /* Store the username part of option if required */
-    if(user_storage) {
-      Curl_safefree(*user_storage);
-      *user_storage = user;
+    if(userp) {
+      Curl_safefree(*userp);
+      *userp = user;
     }
 
     /* Store the password part of option if required */
-    if(pwd_storage) {
-      Curl_safefree(*pwd_storage);
-      *pwd_storage = passwd;
+    if(passwdp) {
+      Curl_safefree(*passwdp);
+      *passwdp = passwd;
     }
 
     /* Store the options part of option if required */
-    if(options_storage) {
-      Curl_safefree(*options_storage);
-      *options_storage = options;
+    if(optionsp) {
+      Curl_safefree(*optionsp);
+      *optionsp = options;
     }
   }
 
-- 
2.4.6


From 956dfd17565bb95ebf8cd7f7a2fe5a76e7da1898 Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Sun, 21 Apr 2013 12:08:35 +0100
Subject: [PATCH 13/28] url: Updated proxy URL parsing to use
 parse_login_details()

Upstream-commit: 11332577b3cbd76f9fc418f3ae11133e4089fa1c
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index 2e691c3..a272087 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -4137,16 +4137,13 @@ static CURLcode parse_proxy(struct SessionHandle *data,
   /* Is there a username and password given in this proxy url? */
   atsign = strchr(proxyptr, '@');
   if(atsign) {
-    char proxyuser[MAX_CURL_USER_LENGTH];
-    char proxypasswd[MAX_CURL_PASSWORD_LENGTH];
-    proxypasswd[0] = 0;
-
-    if(1 <= sscanf(proxyptr,
-                   "%" MAX_CURL_USER_LENGTH_TXT"[^:@]:"
-                   "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]",
-                   proxyuser, proxypasswd)) {
-      CURLcode res = CURLE_OK;
+    CURLcode res = CURLE_OK;
+    char *proxyuser = NULL;
+    char *proxypasswd = NULL;
 
+    res = parse_login_details(proxyptr, atsign - proxyptr,
+                              &proxyuser, &proxypasswd, NULL);
+    if(!res) {
       /* found user and password, rip them out.  note that we are
          unescaping them, as there is otherwise no way to have a
          username or password with reserved characters like ':' in
@@ -4164,7 +4161,7 @@ static CURLcode parse_proxy(struct SessionHandle *data,
           res = CURLE_OUT_OF_MEMORY;
       }
 
-      if(CURLE_OK == res) {
+      if(!res) {
         conn->bits.proxy_user_passwd = TRUE; /* enable it */
         atsign++; /* the right side of the @-letter */
 
@@ -4173,10 +4170,13 @@ static CURLcode parse_proxy(struct SessionHandle *data,
         else
           res = CURLE_OUT_OF_MEMORY;
       }
-
-      if(res)
-        return res;
     }
+
+    Curl_safefree(proxyuser);
+    Curl_safefree(proxypasswd);
+
+    if(res)
+      return res;
   }
 
   /* start scanning for port number at this point */
-- 
2.4.6


From e2480db78651e3d1e2f5939d09b7ada54af0bdf4 Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Sun, 21 Apr 2013 16:55:19 +0100
Subject: [PATCH 14/28] url: Fixed crash when no username or password supplied
 for proxy

Fixed an issue in parse_proxy(), introduced in commit 11332577b3cb,
where an empty username or password (For example: http://:@example.com)
would cause a crash.

Upstream-commit: 416ecc15845c4e6bf7ea6359d9c63adec3385f5b
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index a272087..736f4d9 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -4149,13 +4149,19 @@ static CURLcode parse_proxy(struct SessionHandle *data,
          username or password with reserved characters like ':' in
          them. */
       Curl_safefree(conn->proxyuser);
-      conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL);
+      if(proxyuser)
+        conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL);
+      else
+        conn->proxyuser = strdup("");
 
       if(!conn->proxyuser)
         res = CURLE_OUT_OF_MEMORY;
       else {
         Curl_safefree(conn->proxypasswd);
-        conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL);
+        if(proxypasswd)
+          conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL);
+        else
+          conn->proxypasswd = strdup("");
 
         if(!conn->proxypasswd)
           res = CURLE_OUT_OF_MEMORY;
-- 
2.4.6


From c77ec0c919be4f86cd5fb70fa6813b28b376f48e Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Sun, 21 Apr 2013 18:29:33 +0100
Subject: [PATCH 15/28] url: Fixed missing length check in parse_proxy()

Commit 11332577b3cb removed the length check that was performed by the
old scanf() code.

Upstream-commit: ddac43b38e3fd923b71554126652b05e034d6900
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index 736f4d9..ede7d1c 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -4149,7 +4149,7 @@ static CURLcode parse_proxy(struct SessionHandle *data,
          username or password with reserved characters like ':' in
          them. */
       Curl_safefree(conn->proxyuser);
-      if(proxyuser)
+      if(proxyuser && strlen(proxyuser) < MAX_CURL_USER_LENGTH)
         conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL);
       else
         conn->proxyuser = strdup("");
@@ -4158,7 +4158,7 @@ static CURLcode parse_proxy(struct SessionHandle *data,
         res = CURLE_OUT_OF_MEMORY;
       else {
         Curl_safefree(conn->proxypasswd);
-        if(proxypasswd)
+        if(proxypasswd && strlen(proxypasswd) < MAX_CURL_PASSWORD_LENGTH)
           conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL);
         else
           conn->proxypasswd = strdup("");
-- 
2.4.6


From 4d396dba81cde42581a313a2dbe983a1d985045a Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@redhat.com>
Date: Sun, 30 Jun 2013 19:51:16 +0200
Subject: [PATCH 16/28] url: restore the functionality of 'curl -u :'

This commit fixes a regression introduced in
fddb7b44a79d78e05043e1c97e069308b6b85f79.

Reported by: Markus Moeller
Bug: http://curl.haxx.se/mail/archive-2013-06/0052.html

Upstream-commit: abca89aaa0fb208cfaf4ead6692014c4e553388a
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/lib/url.c b/lib/url.c
index ede7d1c..a2b9abb 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -314,6 +314,13 @@ static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp,
   if(!result) {
     /* Store the username part of option if required */
     if(userp) {
+      if(!user && option && option[0] == ':') {
+        /* Allocate an empty string instead of returning NULL as user name */
+        user = strdup("");
+        if(!user)
+          result = CURLE_OUT_OF_MEMORY;
+      }
+
       Curl_safefree(*userp);
       *userp = user;
     }
-- 
2.4.6


From 0df43fcefa7ba9f47e509b4a55edd6b287dd962e Mon Sep 17 00:00:00 2001
From: Yang Tse <yangsita@gmail.com>
Date: Fri, 12 Jul 2013 12:16:48 +0200
Subject: [PATCH 17/28] url.c: fix parse_login_details() OOM handling

Upstream-commit: 83f0dae1292b8b9b2507457db6b3ab22ba31c64b
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index a2b9abb..61ca8e8 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -4474,15 +4474,20 @@ static CURLcode parse_login_details(const char *login, const size_t len,
   /* Allocate the password portion buffer */
   if(!result && passwdp && plen) {
     pbuf = malloc(plen + 1);
-    if(!pbuf)
+    if(!pbuf) {
+      Curl_safefree(ubuf);
       result = CURLE_OUT_OF_MEMORY;
+    }
   }
 
   /* Allocate the options portion buffer */
   if(!result && optionsp && olen) {
     obuf = malloc(olen + 1);
-    if(!obuf)
+    if(!obuf) {
+      Curl_safefree(pbuf);
+      Curl_safefree(ubuf);
       result = CURLE_OUT_OF_MEMORY;
+    }
   }
 
   if(!result) {
-- 
2.4.6


From 386bc0349e102cbe9a0417688e15ea7e13cf4dd8 Mon Sep 17 00:00:00 2001
From: Yang Tse <yangsita@gmail.com>
Date: Sun, 14 Jul 2013 12:19:57 +0200
Subject: [PATCH 18/28] url.c: fix parse_url_login() OOM handling

Upstream-commit: cfc907e43d5f25a50a9fae95a37a4c0e959d591a
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index 61ca8e8..92a126a 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -4349,8 +4349,12 @@ static CURLcode parse_url_login(struct SessionHandle *data,
 
           /* Decode the user */
           newname = curl_easy_unescape(data, userp, 0, NULL);
-          if(!newname)
+          if(!newname) {
+            Curl_safefree(userp);
+            Curl_safefree(passwdp);
+            Curl_safefree(optionsp);
             return CURLE_OUT_OF_MEMORY;
+          }
 
           if(strlen(newname) < MAX_CURL_USER_LENGTH)
             strcpy(user, newname);
@@ -4361,8 +4365,12 @@ static CURLcode parse_url_login(struct SessionHandle *data,
         if(passwdp) {
           /* We have a password in the URL so decode it */
           char *newpasswd = curl_easy_unescape(data, passwdp, 0, NULL);
-          if(!newpasswd)
+          if(!newpasswd) {
+            Curl_safefree(userp);
+            Curl_safefree(passwdp);
+            Curl_safefree(optionsp);
             return CURLE_OUT_OF_MEMORY;
+          }
 
           if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH)
             strcpy(passwd, newpasswd);
@@ -4373,8 +4381,12 @@ static CURLcode parse_url_login(struct SessionHandle *data,
         if(optionsp) {
           /* We have an options list in the URL so decode it */
           char *newoptions = curl_easy_unescape(data, optionsp, 0, NULL);
-          if(!newoptions)
+          if(!newoptions) {
+            Curl_safefree(userp);
+            Curl_safefree(passwdp);
+            Curl_safefree(optionsp);
             return CURLE_OUT_OF_MEMORY;
+          }
 
           if(strlen(newoptions) < MAX_CURL_OPTIONS_LENGTH)
             strcpy(options, newoptions);
-- 
2.4.6


From ca108f78f894fee22eadf46ec6ef4282d1f23949 Mon Sep 17 00:00:00 2001
From: Jonathan Nieder <jrnieder@gmail.com>
Date: Mon, 19 Aug 2013 00:38:08 -0700
Subject: [PATCH 19/28] url: use goto in create_conn() for exception handling

Instead of remembering before each "return" statement which temporary
allocations, if any, need to be freed, take care to set pointers to
NULL when no longer needed and use a goto to a common block to exit
the function and free all temporaries.

No functional change intended.  Currently the only temporary buffer in
this function is "proxy" which is already correctly freed when
appropriate, but there will be more soon.

Upstream-commit: 53333a43a1959ddeef27c26f0983be1b81e558bc
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 64 +++++++++++++++++++++++++++++++++++++--------------------------
 1 file changed, 38 insertions(+), 26 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index 92a126a..105f2fe 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -4924,8 +4924,10 @@ static CURLcode create_conn(struct SessionHandle *data,
    * Check input data
    *************************************************************/
 
-  if(!data->change.url)
-    return CURLE_URL_MALFORMAT;
+  if(!data->change.url) {
+    result = CURLE_URL_MALFORMAT;
+    goto out;
+  }
 
   /* First, split up the current URL in parts so that we can use the
      parts for checking against the already present connections. In order
@@ -4933,8 +4935,10 @@ static CURLcode create_conn(struct SessionHandle *data,
      connection data struct and fill in for comparison purposes. */
   conn = allocate_conn(data);
 
-  if(!conn)
-    return CURLE_OUT_OF_MEMORY;
+  if(!conn) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
 
   /* We must set the return variable as soon as possible, so that our
      parent can cleanup any possible allocs we may have done before
@@ -4964,15 +4968,18 @@ static CURLcode create_conn(struct SessionHandle *data,
   data->state.path = NULL;
 
   data->state.pathbuffer = malloc(urllen+2);
-  if(NULL == data->state.pathbuffer)
-    return CURLE_OUT_OF_MEMORY; /* really bad error */
+  if(NULL == data->state.pathbuffer) {
+    result = CURLE_OUT_OF_MEMORY; /* really bad error */
+    goto out;
+  }
   data->state.path = data->state.pathbuffer;
 
   conn->host.rawalloc = malloc(urllen+2);
   if(NULL == conn->host.rawalloc) {
     Curl_safefree(data->state.pathbuffer);
     data->state.path = NULL;
-    return CURLE_OUT_OF_MEMORY;
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
   }
 
   conn->host.name = conn->host.rawalloc;
@@ -4981,7 +4988,7 @@ static CURLcode create_conn(struct SessionHandle *data,
   result = parseurlandfillconn(data, conn, &prot_missing, user, passwd,
                                options);
   if(result != CURLE_OK)
-    return result;
+    goto out;
 
   /*************************************************************
    * No protocol part in URL was used, add it!
@@ -4995,8 +5002,8 @@ static CURLcode create_conn(struct SessionHandle *data,
     reurl = aprintf("%s://%s", conn->handler->scheme, data->change.url);
 
     if(!reurl) {
-      Curl_safefree(proxy);
-      return CURLE_OUT_OF_MEMORY;
+      result = CURLE_OUT_OF_MEMORY;
+      goto out;
     }
 
     if(data->change.url_alloc) {
@@ -5033,7 +5040,7 @@ static CURLcode create_conn(struct SessionHandle *data,
   if(conn->bits.proxy_user_passwd) {
     result = parse_proxy_auth(data, conn);
     if(result != CURLE_OK)
-      return result;
+      goto out;
   }
 
   /*************************************************************
@@ -5044,7 +5051,8 @@ static CURLcode create_conn(struct SessionHandle *data,
     /* if global proxy is set, this is it */
     if(NULL == proxy) {
       failf(data, "memory shortage");
-      return CURLE_OUT_OF_MEMORY;
+      result = CURLE_OUT_OF_MEMORY;
+      goto out;
     }
   }
 
@@ -5072,16 +5080,17 @@ static CURLcode create_conn(struct SessionHandle *data,
   if(proxy) {
     result = parse_proxy(data, conn, proxy);
 
-    free(proxy); /* parse_proxy copies the proxy string */
+    Curl_safefree(proxy); /* parse_proxy copies the proxy string */
 
     if(result)
-      return result;
+      goto out;
 
     if((conn->proxytype == CURLPROXY_HTTP) ||
        (conn->proxytype == CURLPROXY_HTTP_1_0)) {
 #ifdef CURL_DISABLE_HTTP
       /* asking for a HTTP proxy is a bit funny when HTTP is disabled... */
-      return CURLE_UNSUPPORTED_PROTOCOL;
+      result = CURLE_UNSUPPORTED_PROTOCOL;
+      goto out;
 #else
       /* force this connection's protocol to become HTTP if not already
          compatible - if it isn't tunneling through */
@@ -5111,10 +5120,8 @@ static CURLcode create_conn(struct SessionHandle *data,
    * we figured out what/if proxy to use.
    *************************************************************/
   result = setup_connection_internals(conn);
-  if(result != CURLE_OK) {
-    Curl_safefree(proxy);
-    return result;
-  }
+  if(result != CURLE_OK)
+    goto out;
 
   conn->recv[FIRSTSOCKET] = Curl_recv_plain;
   conn->send[FIRSTSOCKET] = Curl_send_plain;
@@ -5147,7 +5154,7 @@ static CURLcode create_conn(struct SessionHandle *data,
         DEBUGASSERT(conn->handler->done);
         /* we ignore the return code for the protocol-specific DONE */
         (void)conn->handler->done(conn, result, FALSE);
-        return result;
+        goto out;
       }
 
       Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
@@ -5157,7 +5164,7 @@ static CURLcode create_conn(struct SessionHandle *data,
     /* since we skip do_init() */
     Curl_speedinit(data);
 
-    return result;
+    goto out;
   }
 #endif
 
@@ -5173,13 +5180,13 @@ static CURLcode create_conn(struct SessionHandle *data,
    *************************************************************/
   result = parse_remote_port(data, conn);
   if(result != CURLE_OK)
-    return result;
+    goto out;
 
   /* Check for overridden login details and set them accordingly */
   override_login(data, conn, user, passwd, options);
   result = set_login(conn, user, passwd, options);
   if(result != CURLE_OK)
-    return result;
+    goto out;
 
   /* Get a cloned copy of the SSL config situation stored in the
      connection struct. But to get this going nicely, we must first make
@@ -5202,8 +5209,10 @@ static CURLcode create_conn(struct SessionHandle *data,
   data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD];
 #endif
 
-  if(!Curl_clone_ssl_config(&data->set.ssl, &conn->ssl_config))
-    return CURLE_OUT_OF_MEMORY;
+  if(!Curl_clone_ssl_config(&data->set.ssl, &conn->ssl_config)) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
 
   /*************************************************************
    * Check the current list of connections to see if we can
@@ -5256,7 +5265,7 @@ static CURLcode create_conn(struct SessionHandle *data,
    */
   result = setup_range(data);
   if(result)
-    return result;
+    goto out;
 
   /* Continue connectdata initialization here. */
 
@@ -5274,6 +5283,9 @@ static CURLcode create_conn(struct SessionHandle *data,
    *************************************************************/
   result = resolve_server(data, conn, async);
 
+  out:
+
+  Curl_safefree(proxy);
   return result;
 }
 
-- 
2.4.6


From 2f81fdaa7a966ba8e0bfaae29d86426b7e8159bd Mon Sep 17 00:00:00 2001
From: Jonathan Nieder <jrnieder@gmail.com>
Date: Mon, 19 Aug 2013 00:39:05 -0700
Subject: [PATCH 20/28] url: allocate username, password, and options on the
 heap

This makes it possible to increase the size of the buffers when needed
in later patches.  No functional change yet.

Upstream-commit: 11baffbff67eae225f63fc684d80ce52a79c8ac5
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index 105f2fe..6bce0bb 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -4911,9 +4911,9 @@ static CURLcode create_conn(struct SessionHandle *data,
   struct connectdata *conn;
   struct connectdata *conn_temp = NULL;
   size_t urllen;
-  char user[MAX_CURL_USER_LENGTH];
-  char passwd[MAX_CURL_PASSWORD_LENGTH];
-  char options[MAX_CURL_OPTIONS_LENGTH];
+  char *user = NULL;
+  char *passwd = NULL;
+  char *options = NULL;
   bool reuse;
   char *proxy = NULL;
   bool prot_missing = FALSE;
@@ -4985,6 +4985,14 @@ static CURLcode create_conn(struct SessionHandle *data,
   conn->host.name = conn->host.rawalloc;
   conn->host.name[0] = 0;
 
+  user = malloc(MAX_CURL_USER_LENGTH);
+  passwd = malloc(MAX_CURL_PASSWORD_LENGTH);
+  options = malloc(MAX_CURL_OPTIONS_LENGTH);
+  if(!user || !passwd || !options) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
+
   result = parseurlandfillconn(data, conn, &prot_missing, user, passwd,
                                options);
   if(result != CURLE_OK)
@@ -5285,6 +5293,9 @@ static CURLcode create_conn(struct SessionHandle *data,
 
   out:
 
+  Curl_safefree(options);
+  Curl_safefree(passwd);
+  Curl_safefree(user);
   Curl_safefree(proxy);
   return result;
 }
-- 
2.4.6


From 978711e025bcbd1654758b648db4317d0e446f84 Mon Sep 17 00:00:00 2001
From: Jonathan Nieder <jrnieder@gmail.com>
Date: Mon, 19 Aug 2013 00:48:24 -0700
Subject: [PATCH 21/28] netrc: handle longer username and password

libcurl truncates usernames and passwords it reads from .netrc to
LOGINSIZE and PASSWORDSIZE (64) characters without any indication to
the user, to ensure the values returned from Curl_parsenetrc fit in a
caller-provided buffer.

Fix the interface by passing back dynamically allocated buffers
allocated to fit the user's input.  The parser still relies on a
256-character buffer to read each line, though.

So now you can include an ~246-character password in your .netrc,
instead of the previous limit of 63 characters.

Reported-by: Colby Ranger

Upstream-commit: 36585b539543ca4471ab19c0d738a6e52a827aee
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/netrc.c           | 20 ++++++++++++-------
 lib/netrc.h           | 16 ++++++----------
 lib/url.c             | 18 ++++++++---------
 tests/unit/unit1304.c | 53 ++++++++++++++++++++++++++++++---------------------
 4 files changed, 59 insertions(+), 48 deletions(-)

diff --git a/lib/netrc.c b/lib/netrc.c
index 2c5942a..f51fdf3 100644
--- a/lib/netrc.c
+++ b/lib/netrc.c
@@ -52,13 +52,13 @@ enum host_lookup_state {
  * @unittest: 1304
  */
 int Curl_parsenetrc(const char *host,
-                    char *login,
-                    char *password,
+                    char **loginp,
+                    char **passwordp,
                     char *netrcfile)
 {
   FILE *file;
   int retcode=1;
-  int specific_login = (login[0] != 0);
+  int specific_login = (**loginp != 0);
   char *home = NULL;
   bool home_alloc = FALSE;
   bool netrc_alloc = FALSE;
@@ -109,7 +109,7 @@ int Curl_parsenetrc(const char *host,
       tok=strtok_r(netrcbuffer, " \t\n", &tok_buf);
       while(!done && tok) {
 
-        if(login[0] && password[0]) {
+        if(**loginp && **passwordp) {
           done=TRUE;
           break;
         }
@@ -138,16 +138,22 @@ int Curl_parsenetrc(const char *host,
           /* we are now parsing sub-keywords concerning "our" host */
           if(state_login) {
             if(specific_login) {
-              state_our_login = Curl_raw_equal(login, tok);
+              state_our_login = Curl_raw_equal(*loginp, tok);
             }
             else {
-              strncpy(login, tok, LOGINSIZE-1);
+              free(*loginp);
+              *loginp = strdup(tok);
+              if(!*loginp)
+                return -1; /* allocation failed */
             }
             state_login=0;
           }
           else if(state_password) {
             if(state_our_login || !specific_login) {
-              strncpy(password, tok, PASSWORDSIZE-1);
+              free(*passwordp);
+              *passwordp = strdup(tok);
+              if(!*passwordp)
+                return -1; /* allocation failed */
             }
             state_password=0;
           }
diff --git a/lib/netrc.h b/lib/netrc.h
index 4db764d..a145601 100644
--- a/lib/netrc.h
+++ b/lib/netrc.h
@@ -22,19 +22,15 @@
  *
  ***************************************************************************/
 
-/* Make sure we have room for at least this size: */
-#define LOGINSIZE 64
-#define PASSWORDSIZE 64
-
 /* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */
 int Curl_parsenetrc(const char *host,
-                    char *login,
-                    char *password,
+                    char **loginp,
+                    char **passwordp,
                     char *filename);
-  /* Assume: password[0]=0, host[0] != 0.
-   * If login[0] = 0, search for login and password within a machine section
-   * in the netrc.
-   * If login[0] != 0, search for password within machine and login.
+  /* Assume: (*passwordp)[0]=0, host[0] != 0.
+   * If (*loginp)[0] = 0, search for login and password within a machine
+   * section in the netrc.
+   * If (*loginp)[0] != 0, search for password within machine and login.
    */
 
 #endif /* HEADER_CURL_NETRC_H */
diff --git a/lib/url.c b/lib/url.c
index 6bce0bb..406ef85 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -4656,27 +4656,27 @@ static CURLcode parse_remote_port(struct SessionHandle *data,
  */
 static void override_login(struct SessionHandle *data,
                            struct connectdata *conn,
-                           char *user, char *passwd, char *options)
+                           char **userp, char **passwdp, char **optionsp)
 {
   if(data->set.str[STRING_USERNAME]) {
-    strncpy(user, data->set.str[STRING_USERNAME], MAX_CURL_USER_LENGTH);
-    user[MAX_CURL_USER_LENGTH - 1] = '\0';   /* To be on safe side */
+    strncpy(*userp, data->set.str[STRING_USERNAME], MAX_CURL_USER_LENGTH);
+    (*userp)[MAX_CURL_USER_LENGTH - 1] = '\0';   /* To be on safe side */
   }
 
   if(data->set.str[STRING_PASSWORD]) {
-    strncpy(passwd, data->set.str[STRING_PASSWORD], MAX_CURL_PASSWORD_LENGTH);
-    passwd[MAX_CURL_PASSWORD_LENGTH - 1] = '\0'; /* To be on safe side */
+    strncpy(*passwdp, data->set.str[STRING_PASSWORD], MAX_CURL_PASSWORD_LENGTH);
+    (*passwdp)[MAX_CURL_PASSWORD_LENGTH - 1] = '\0'; /* To be on safe side */
   }
 
   if(data->set.str[STRING_OPTIONS]) {
-    strncpy(options, data->set.str[STRING_OPTIONS], MAX_CURL_OPTIONS_LENGTH);
-    options[MAX_CURL_OPTIONS_LENGTH - 1] = '\0'; /* To be on safe side */
+    strncpy(*optionsp, data->set.str[STRING_OPTIONS], MAX_CURL_OPTIONS_LENGTH);
+    (*optionsp)[MAX_CURL_OPTIONS_LENGTH - 1] = '\0'; /* To be on safe side */
   }
 
   conn->bits.netrc = FALSE;
   if(data->set.use_netrc != CURL_NETRC_IGNORED) {
     if(Curl_parsenetrc(conn->host.name,
-                       user, passwd,
+                       userp, passwdp,
                        data->set.str[STRING_NETRC_FILE])) {
       infof(data, "Couldn't find host %s in the "
             DOT_CHAR "netrc file; using defaults\n",
@@ -5191,7 +5191,7 @@ static CURLcode create_conn(struct SessionHandle *data,
     goto out;
 
   /* Check for overridden login details and set them accordingly */
-  override_login(data, conn, user, passwd, options);
+  override_login(data, conn, &user, &passwd, &options);
   result = set_login(conn, user, passwd, options);
   if(result != CURLE_OK)
     goto out;
diff --git a/tests/unit/unit1304.c b/tests/unit/unit1304.c
index 8ddd8ca..9242e80 100644
--- a/tests/unit/unit1304.c
+++ b/tests/unit/unit1304.c
@@ -23,14 +23,14 @@
 
 #include "netrc.h"
 
-static char login[LOGINSIZE];
-static char password[PASSWORDSIZE];
+static char *login;
+static char *password;
 static char filename[64];
 
 static CURLcode unit_setup(void)
 {
-  password[0] = 0;
-  login[0] = 0;
+  password = strdup("");
+  login = strdup("");
   return CURLE_OK;
 }
 
@@ -47,7 +47,7 @@ UNITTEST_START
   /*
    * Test a non existent host in our netrc file.
    */
-  result = Curl_parsenetrc("test.example.com", login, password, filename);
+  result = Curl_parsenetrc("test.example.com", &login, &password, filename);
   fail_unless(result == 1, "Host not found should return 1");
   fail_unless(password[0] == 0, "password should not have been changed");
   fail_unless(login[0] == 0, "login should not have been changed");
@@ -55,8 +55,9 @@ UNITTEST_START
   /*
    * Test a non existent login in our netrc file.
    */
-  memcpy(login, "me", 2);
-  result = Curl_parsenetrc("example.com", login, password, filename);
+  free(login);
+  login = strdup("me");
+  result = Curl_parsenetrc("example.com", &login, &password, filename);
   fail_unless(result == 0, "Host should be found");
   fail_unless(password[0] == 0, "password should not have been changed");
   fail_unless(strncmp(login, "me", 2) == 0, "login should not have been changed");
@@ -64,8 +65,9 @@ UNITTEST_START
   /*
    * Test a non existent login and host in our netrc file.
    */
-  memcpy(login, "me", 2);
-  result = Curl_parsenetrc("test.example.com", login, password, filename);
+  free(login);
+  login = strdup("me");
+  result = Curl_parsenetrc("test.example.com", &login, &password, filename);
   fail_unless(result == 1, "Host should be found");
   fail_unless(password[0] == 0, "password should not have been changed");
   fail_unless(strncmp(login, "me", 2) == 0, "login should not have been changed");
@@ -74,8 +76,9 @@ UNITTEST_START
    * Test a non existent login (substring of an existing one) in our
    * netrc file.
    */
-  memcpy(login, "admi", 4);
-  result = Curl_parsenetrc("example.com", login, password, filename);
+  free(login);
+  login = strdup("admi");
+  result = Curl_parsenetrc("example.com", &login, &password, filename);
   fail_unless(result == 0, "Host should be found");
   fail_unless(password[0] == 0, "password should not have been changed");
   fail_unless(strncmp(login, "admi", 4) == 0, "login should not have been changed");
@@ -84,8 +87,9 @@ UNITTEST_START
    * Test a non existent login (superstring of an existing one)
    * in our netrc file.
    */
-  memcpy(login, "adminn", 6);
-  result = Curl_parsenetrc("example.com", login, password, filename);
+  free(login);
+  login = strdup("adminn");
+  result = Curl_parsenetrc("example.com", &login, &password, filename);
   fail_unless(result == 0, "Host should be found");
   fail_unless(password[0] == 0, "password should not have been changed");
   fail_unless(strncmp(login, "adminn", 6) == 0, "login should not have been changed");
@@ -94,8 +98,9 @@ UNITTEST_START
    * Test for the first existing host in our netrc file
    * with login[0] = 0.
    */
-  login[0] = 0;
-  result = Curl_parsenetrc("example.com", login, password, filename);
+  free(login);
+  login = strdup("");
+  result = Curl_parsenetrc("example.com", &login, &password, filename);
   fail_unless(result == 0, "Host should have been found");
   fail_unless(strncmp(password, "passwd", 6) == 0,
               "password should be 'passwd'");
@@ -105,8 +110,9 @@ UNITTEST_START
    * Test for the first existing host in our netrc file
    * with login[0] != 0.
    */
-  password[0] = 0;
-  result = Curl_parsenetrc("example.com", login, password, filename);
+  free(password);
+  password = strdup("");
+  result = Curl_parsenetrc("example.com", &login, &password, filename);
   fail_unless(result == 0, "Host should have been found");
   fail_unless(strncmp(password, "passwd", 6) == 0,
               "password should be 'passwd'");
@@ -116,9 +122,11 @@ UNITTEST_START
    * Test for the second existing host in our netrc file
    * with login[0] = 0.
    */
-  password[0] = 0;
-  login[0] = 0;
-  result = Curl_parsenetrc("curl.example.com", login, password, filename);
+  free(password);
+  password = strdup("");
+  free(login);
+  login = strdup("");
+  result = Curl_parsenetrc("curl.example.com", &login, &password, filename);
   fail_unless(result == 0, "Host should have been found");
   fail_unless(strncmp(password, "none", 4) == 0,
               "password should be 'none'");
@@ -128,8 +136,9 @@ UNITTEST_START
    * Test for the second existing host in our netrc file
    * with login[0] != 0.
    */
-  password[0] = 0;
-  result = Curl_parsenetrc("curl.example.com", login, password, filename);
+  free(password);
+  password = strdup("");
+  result = Curl_parsenetrc("curl.example.com", &login, &password, filename);
   fail_unless(result == 0, "Host should have been found");
   fail_unless(strncmp(password, "none", 4) == 0,
               "password should be 'none'");
-- 
2.4.6


From 96b625ddedb692a41b173cabf0bd5913f4535c70 Mon Sep 17 00:00:00 2001
From: Jonathan Nieder <jrnieder@gmail.com>
Date: Mon, 19 Aug 2013 00:57:54 -0700
Subject: [PATCH 22/28] 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

Upstream-commit: 15f76bf7bb92b315799541b0e5127c8d22a50733
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 29 +++++++++++++++++++----------
 1 file changed, 19 insertions(+), 10 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index 406ef85..515fa67 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -4654,23 +4654,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,
-                           struct connectdata *conn,
-                           char **userp, char **passwdp, char **optionsp)
+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;
@@ -4691,6 +4697,7 @@ static void override_login(struct SessionHandle *data,
       conn->bits.user_passwd = TRUE; /* enable user+password */
     }
   }
+  return CURLE_OK;
 }
 
 /*
@@ -5191,7 +5198,9 @@ static CURLcode create_conn(struct SessionHandle *data,
     goto out;
 
   /* Check for overridden login details and set them accordingly */
-  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;
-- 
2.4.6


From d2fa706f006d393eee63ed686efccf68db5b6337 Mon Sep 17 00:00:00 2001
From: Jonathan Nieder <jrnieder@gmail.com>
Date: Mon, 19 Aug 2013 01:01:26 -0700
Subject: [PATCH 23/28] url: handle exceptional cases first in
 parse_url_login()

Instead of nesting "if(success)" blocks and leaving the reader in
suspense about what happens in the !success case, deal with failure
cases early, usually with a simple goto to clean up and return from
the function.

No functional change intended.  The main effect is to decrease the
indentation of this function slightly.

Upstream-commit: 09ddb1d61cdb9ee11ebf481b29dac1be8f0ab848
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 121 ++++++++++++++++++++++++++++++--------------------------------
 1 file changed, 59 insertions(+), 62 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index 515fa67..8fff5ef 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -4321,86 +4321,83 @@ static CURLcode parse_url_login(struct SessionHandle *data,
   passwd[0] = 0;
   options[0] = 0;
 
+  if(!ptr)
+    goto out;
+
   /* We will now try to extract the
    * possible login information in a string like:
    * ftp://user:password@ftp.my.site:8021/README */
-  if(ptr) {
-    /* There's login information to the left of the @ */
+  conn->host.name = ++ptr;
 
-    conn->host.name = ++ptr;
+  /* So the hostname is sane.  Only bother interpreting the
+   * results if we could care.  It could still be wasted
+   * work because it might be overtaken by the programmatically
+   * set user/passwd, but doing that first adds more cases here :-(
+   */
 
-    /* So the hostname is sane.  Only bother interpreting the
-     * results if we could care.  It could still be wasted
-     * work because it might be overtaken by the programmatically
-     * set user/passwd, but doing that first adds more cases here :-(
-     */
+  if(data->set.use_netrc == CURL_NETRC_REQUIRED)
+    goto out;
 
-    if(data->set.use_netrc != CURL_NETRC_REQUIRED) {
-      /* We could use the login information in the URL so extract it */
-      result = parse_login_details(login, ptr - login - 1,
-                                   &userp, &passwdp, &optionsp);
-      if(!result) {
-        if(userp) {
-          char *newname;
-
-          /* We have a user in the URL */
-          conn->bits.userpwd_in_url = TRUE;
-          conn->bits.user_passwd = TRUE; /* enable user+password */
-
-          /* Decode the user */
-          newname = curl_easy_unescape(data, userp, 0, NULL);
-          if(!newname) {
-            Curl_safefree(userp);
-            Curl_safefree(passwdp);
-            Curl_safefree(optionsp);
-            return CURLE_OUT_OF_MEMORY;
-          }
+  /* We could use the login information in the URL so extract it */
+  result = parse_login_details(login, ptr - login - 1,
+                               &userp, &passwdp, &optionsp);
+  if(result != CURLE_OK)
+    goto out;
 
-          if(strlen(newname) < MAX_CURL_USER_LENGTH)
-            strcpy(user, newname);
+  if(userp) {
+    char *newname;
 
-          free(newname);
-        }
+    /* We have a user in the URL */
+    conn->bits.userpwd_in_url = TRUE;
+    conn->bits.user_passwd = TRUE; /* enable user+password */
 
-        if(passwdp) {
-          /* We have a password in the URL so decode it */
-          char *newpasswd = curl_easy_unescape(data, passwdp, 0, NULL);
-          if(!newpasswd) {
-            Curl_safefree(userp);
-            Curl_safefree(passwdp);
-            Curl_safefree(optionsp);
-            return CURLE_OUT_OF_MEMORY;
-          }
+    /* Decode the user */
+    newname = curl_easy_unescape(data, userp, 0, NULL);
+    if(!newname) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto out;
+    }
 
-          if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH)
-            strcpy(passwd, newpasswd);
+    if(strlen(newname) < MAX_CURL_USER_LENGTH)
+      strcpy(user, newname);
 
-          free(newpasswd);
-        }
+    free(newname);
+  }
 
-        if(optionsp) {
-          /* We have an options list in the URL so decode it */
-          char *newoptions = curl_easy_unescape(data, optionsp, 0, NULL);
-          if(!newoptions) {
-            Curl_safefree(userp);
-            Curl_safefree(passwdp);
-            Curl_safefree(optionsp);
-            return CURLE_OUT_OF_MEMORY;
-          }
+  if(passwdp) {
+    /* We have a password in the URL so decode it */
+    char *newpasswd = curl_easy_unescape(data, passwdp, 0, NULL);
+    if(!newpasswd) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto out;
+    }
 
-          if(strlen(newoptions) < MAX_CURL_OPTIONS_LENGTH)
-            strcpy(options, newoptions);
+    if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH)
+      strcpy(passwd, newpasswd);
 
-          free(newoptions);
-        }
-      }
+    free(newpasswd);
+  }
 
-      Curl_safefree(userp);
-      Curl_safefree(passwdp);
-      Curl_safefree(optionsp);
+  if(optionsp) {
+    /* We have an options list in the URL so decode it */
+    char *newoptions = curl_easy_unescape(data, optionsp, 0, NULL);
+    if(!newoptions) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto out;
     }
+
+    if(strlen(newoptions) < MAX_CURL_OPTIONS_LENGTH)
+      strcpy(options, newoptions);
+
+    free(newoptions);
   }
 
+  out:
+
+  Curl_safefree(userp);
+  Curl_safefree(passwdp);
+  Curl_safefree(optionsp);
+
   return result;
 }
 
-- 
2.4.6


From 085588f8f1baa68a28e0cc3b7197fcb3f99b8f15 Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Sun, 21 Apr 2013 12:11:50 +0100
Subject: [PATCH 24/28] url: Removed unused text length constants

Upstream-commit: 455ba691a7250b312075a5d91ae89bbbe70d62aa
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/urldata.h | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/lib/urldata.h b/lib/urldata.h
index 1c2281a..219a11a 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1134,9 +1134,6 @@ typedef enum {
 #define MAX_CURL_USER_LENGTH 256
 #define MAX_CURL_PASSWORD_LENGTH 256
 #define MAX_CURL_OPTIONS_LENGTH 256
-#define MAX_CURL_USER_LENGTH_TXT "255"
-#define MAX_CURL_PASSWORD_LENGTH_TXT "255"
-#define MAX_CURL_OPTIONS_LENGTH_TXT "255"
 
 struct auth {
   unsigned long want;  /* Bitmask set to the authentication methods wanted by
-- 
2.4.6


From 314f6398307783780f416d834295002c4b745251 Mon Sep 17 00:00:00 2001
From: Jonathan Nieder <jrnieder@gmail.com>
Date: Mon, 19 Aug 2013 01:36:46 -0700
Subject: [PATCH 25/28] url: handle arbitrary-length username and password
 before '@'

libcurl quietly truncates usernames, passwords, and options from
before an '@' sign in a URL to 255 (= MAX_CURL_PASSWORD_LENGTH - 1)
characters to fit in fixed-size buffers on the stack.  Allocate a
buffer large enough to fit the parsed fields on the fly instead to
support longer passwords.

After this change, there are no more uses of MAX_CURL_OPTIONS_LENGTH
left, so stop defining that constant while at it.  The hardcoded max
username and password length constants, on the other hand, are still
used in HTTP proxy credential handling (which this patch doesn't
touch).

Reported-by: Colby Ranger

Upstream-commit: 2f1a0bc0bf36c5ad0f8755d9c7553e1f5729af43
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c     | 45 +++++++++++++++++++++------------------------
 lib/urldata.h |  1 -
 2 files changed, 21 insertions(+), 25 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index 8fff5ef..abf8a43 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -140,7 +140,8 @@ static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke);
 static CURLcode do_init(struct connectdata *conn);
 static CURLcode parse_url_login(struct SessionHandle *data,
                                 struct connectdata *conn,
-                                char *user, char *passwd, char *options);
+                                char **userptr, char **passwdptr,
+                                char **optionsptr);
 static CURLcode parse_login_details(const char *login, const size_t len,
                                     char **userptr, char **passwdptr,
                                     char **optionsptr);
@@ -3595,7 +3596,8 @@ static CURLcode findprotocol(struct SessionHandle *data,
 static CURLcode parseurlandfillconn(struct SessionHandle *data,
                                     struct connectdata *conn,
                                     bool *prot_missing,
-                                    char *user, char *passwd, char *options)
+                                    char **userp, char **passwdp,
+                                    char **optionsp)
 {
   char *at;
   char *fragment;
@@ -3820,7 +3822,7 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data,
    * Parse the login details from the URL and strip them out of
    * the host name
    */
-  result = parse_url_login(data, conn, user, passwd, options);
+  result = parse_url_login(data, conn, userp, passwdp, optionsp);
   if(result != CURLE_OK)
     return result;
 
@@ -4300,7 +4302,7 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data,
  */
 static CURLcode parse_url_login(struct SessionHandle *data,
                                 struct connectdata *conn,
-                                char *user, char *passwd, char *options)
+                                char **user, char **passwd, char **options)
 {
   CURLcode result = CURLE_OK;
   char *userp = NULL;
@@ -4317,9 +4319,9 @@ static CURLcode parse_url_login(struct SessionHandle *data,
   char *ptr = strchr(conn->host.name, '@');
   char *login = conn->host.name;
 
-  user[0] = 0;   /* to make everything well-defined */
-  passwd[0] = 0;
-  options[0] = 0;
+  DEBUGASSERT(!**user);
+  DEBUGASSERT(!**passwd);
+  DEBUGASSERT(!**options);
 
   if(!ptr)
     goto out;
@@ -4358,10 +4360,8 @@ static CURLcode parse_url_login(struct SessionHandle *data,
       goto out;
     }
 
-    if(strlen(newname) < MAX_CURL_USER_LENGTH)
-      strcpy(user, newname);
-
-    free(newname);
+    free(*user);
+    *user = newname;
   }
 
   if(passwdp) {
@@ -4372,10 +4372,8 @@ static CURLcode parse_url_login(struct SessionHandle *data,
       goto out;
     }
 
-    if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH)
-      strcpy(passwd, newpasswd);
-
-    free(newpasswd);
+    free(*passwd);
+    *passwd = newpasswd;
   }
 
   if(optionsp) {
@@ -4386,12 +4384,11 @@ static CURLcode parse_url_login(struct SessionHandle *data,
       goto out;
     }
 
-    if(strlen(newoptions) < MAX_CURL_OPTIONS_LENGTH)
-      strcpy(options, newoptions);
-
-    free(newoptions);
+    free(*options);
+    *options = newoptions;
   }
 
+
   out:
 
   Curl_safefree(userp);
@@ -4989,16 +4986,16 @@ static CURLcode create_conn(struct SessionHandle *data,
   conn->host.name = conn->host.rawalloc;
   conn->host.name[0] = 0;
 
-  user = malloc(MAX_CURL_USER_LENGTH);
-  passwd = malloc(MAX_CURL_PASSWORD_LENGTH);
-  options = malloc(MAX_CURL_OPTIONS_LENGTH);
+  user = strdup("");
+  passwd = strdup("");
+  options = strdup("");
   if(!user || !passwd || !options) {
     result = CURLE_OUT_OF_MEMORY;
     goto out;
   }
 
-  result = parseurlandfillconn(data, conn, &prot_missing, user, passwd,
-                               options);
+  result = parseurlandfillconn(data, conn, &prot_missing, &user, &passwd,
+                               &options);
   if(result != CURLE_OK)
     goto out;
 
diff --git a/lib/urldata.h b/lib/urldata.h
index 219a11a..b3ee7e3 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1133,7 +1133,6 @@ typedef enum {
  * Session-data MUST be put in the connectdata struct and here.  */
 #define MAX_CURL_USER_LENGTH 256
 #define MAX_CURL_PASSWORD_LENGTH 256
-#define MAX_CURL_OPTIONS_LENGTH 256
 
 struct auth {
   unsigned long want;  /* Bitmask set to the authentication methods wanted by
-- 
2.4.6


From 806203027b9dae8992f9762b056e953ecb118b84 Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Sun, 1 Sep 2013 13:30:12 +0100
Subject: [PATCH 26/28] url.c: Fixed compilation warning

An enumerated type is mixed with another type

Upstream-commit: 322f0bc2f1af4a985e85ee5c8639e3b454314ccd
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index abf8a43..558799c 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -4648,9 +4648,9 @@ 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 int override_login(struct SessionHandle *data,
-                          struct connectdata *conn,
-                          char **userp, char **passwdp, char **optionsp)
+static CURLcode override_login(struct SessionHandle *data,
+                               struct connectdata *conn,
+                               char **userp, char **passwdp, char **optionsp)
 {
   if(data->set.str[STRING_USERNAME]) {
     free(*userp);
@@ -4691,6 +4691,7 @@ static int override_login(struct SessionHandle *data,
       conn->bits.user_passwd = TRUE; /* enable user+password */
     }
   }
+
   return CURLE_OK;
 }
 
-- 
2.4.6


From 7ed75f9bce576390e2c94a797c4520130654b416 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Sat, 14 Dec 2013 22:39:27 +0100
Subject: [PATCH 27/28] login options: remove the ;[options] support from
 CURLOPT_USERPWD

To avoid the regression when users pass in passwords containing semi-
colons, we now drop the ability to set the login options with the same
options. Support for login options in CURLOPT_USERPWD was added in
7.31.0.

Test case 83 was modified to verify that colons and semi-colons can be
used as part of the password when using -u (CURLOPT_USERPWD).

Bug: http://curl.haxx.se/bug/view.cgi?id=1311
Reported-by: Petr Bahula
Assisted-by: Steve Holme
Signed-off-by: Daniel Stenberg <daniel@haxx.se>

Upstream-commit: 169fedbdce93ecf14befb6e0e1ce6a2d480252a3
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c         | 19 +++++--------------
 tests/data/test83 |  4 ++--
 2 files changed, 7 insertions(+), 16 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index 558799c..8c76256 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -295,13 +295,11 @@ static CURLcode setstropt(char **charp, char *s)
   return CURLE_OK;
 }
 
-static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp,
-                                  char **optionsp)
+static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp)
 {
   CURLcode result = CURLE_OK;
   char *user = NULL;
   char *passwd = NULL;
-  char *options = NULL;
 
   /* Parse the login details if specified. It not then we treat NULL as a hint
      to clear the existing data */
@@ -309,7 +307,7 @@ static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp,
     result = parse_login_details(option, strlen(option),
                                  (userp ? &user : NULL),
                                  (passwdp ? &passwd : NULL),
-                                 (optionsp ? &options : NULL));
+                                 NULL);
   }
 
   if(!result) {
@@ -331,12 +329,6 @@ static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp,
       Curl_safefree(*passwdp);
       *passwdp = passwd;
     }
-
-    /* Store the options part of option if required */
-    if(optionsp) {
-      Curl_safefree(*optionsp);
-      *optionsp = options;
-    }
   }
 
   return result;
@@ -1553,12 +1545,11 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
 
   case CURLOPT_USERPWD:
     /*
-     * user:password;options to use in the operation
+     * user:password to use in the operation
      */
     result = setstropt_userpwd(va_arg(param, char *),
                                &data->set.str[STRING_USERNAME],
-                               &data->set.str[STRING_PASSWORD],
-                               &data->set.str[STRING_OPTIONS]);
+                               &data->set.str[STRING_PASSWORD]);
     break;
   case CURLOPT_USERNAME:
     /*
@@ -1631,7 +1622,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      */
     result = setstropt_userpwd(va_arg(param, char *),
                                &data->set.str[STRING_PROXYUSERNAME],
-                               &data->set.str[STRING_PROXYPASSWORD], NULL);
+                               &data->set.str[STRING_PROXYPASSWORD]);
     break;
   case CURLOPT_PROXYUSERNAME:
     /*
diff --git a/tests/data/test83 b/tests/data/test83
index 3015c9c..160b40c 100644
--- a/tests/data/test83
+++ b/tests/data/test83
@@ -46,7 +46,7 @@ http-proxy
 HTTP over proxy-tunnel with site authentication
  </name>
  <command>
-http://%HOSTIP:%HTTPPORT/we/want/that/page/83 -p -x %HOSTIP:%PROXYPORT --user iam:myself
+http://%HOSTIP:%HTTPPORT/we/want/that/page/83 -p -x %HOSTIP:%PROXYPORT --user 'iam:my:;self'
 </command>
 </client>
 
@@ -65,7 +65,7 @@ Proxy-Connection: Keep-Alive
 </proxy>
 <protocol>
 GET /we/want/that/page/83 HTTP/1.1
-Authorization: Basic aWFtOm15c2VsZg==
+Authorization: Basic aWFtOm15OjtzZWxm
 User-Agent: curl/7.10.7-pre2 (i686-pc-linux-gnu) libcurl/7.10.7-pre2 OpenSSL/0.9.7a zlib/1.1.3
 Host: %HOSTIP:%HTTPPORT
 Accept: */*
-- 
2.4.6


From ffe3cb2b365e914e364a6c9d7611e6e7f60d3cfa Mon Sep 17 00:00:00 2001
From: Dan Fandrich <dan@coneharvesters.com>
Date: Wed, 29 Jan 2014 08:10:26 +0100
Subject: [PATCH 28/28] netrc: Fixed a memory leak in an OOM condition

Upstream-commit: 768151449b386488ac8fe869f48bf2930123d601
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index 8c76256..57944e4 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -4666,13 +4666,17 @@ static CURLcode override_login(struct SessionHandle *data,
 
   conn->bits.netrc = FALSE;
   if(data->set.use_netrc != CURL_NETRC_IGNORED) {
-    if(Curl_parsenetrc(conn->host.name,
-                       userp, passwdp,
-                       data->set.str[STRING_NETRC_FILE])) {
+    int 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 "
             DOT_CHAR "netrc file; using defaults\n",
             conn->host.name);
     }
+    else if(ret < 0 ) {
+      return CURLE_OUT_OF_MEMORY;
+    }
     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
-- 
2.4.6