cURL / Mailing Lists / curl-library / Single Mail

curl-library

[PATCH curl 4/7] netrc: handle longer username and password

From: Jonathan Nieder <jrnieder_at_gmail.com>
Date: Tue, 20 Aug 2013 00:50:30 -0700

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

---
Change since v1:
- line-wrapped comment in netrc.h
 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 2c5942af..f51fdf34 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 4db764df..a1456011 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 07555a90..8b628582 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -4795,27 +4795,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",
@@ -5278,7 +5278,7 @@ static CURLcode create_conn(struct SessionHandle *data,
 
   /* Check for overridden login details and set them accordingly so they
      they are known when protocol->setup_connection is called! */
-  override_login(data, conn, user, passwd, options);
+  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 8ddd8cae..9242e800 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'");
-- 
1.8.4.rc4
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html
Received on 2013-08-20