MACDEF
};
+enum found_state {
+ NONE,
+ LOGIN,
+ PASSWORD
+};
+
+#define FOUND_LOGIN 1
+#define FOUND_PASSWORD 2
+
#define NETRC_FILE_MISSING 1
#define NETRC_FAILED -1
#define NETRC_SUCCESS 0
* Returns zero on success.
*/
static int parsenetrc(const char *host,
- char **loginp,
+ char **loginp, /* might point to a username */
char **passwordp,
char *netrcfile)
{
FILE *file;
int retcode = NETRC_FILE_MISSING;
char *login = *loginp;
- char *password = *passwordp;
- bool specific_login = (login && *login != 0);
- bool login_alloc = FALSE;
- bool password_alloc = FALSE;
+ char *password = NULL;
+ bool specific_login = login; /* points to something */
enum host_lookup_state state = NOTHING;
-
- char state_login = 0; /* Found a login keyword */
- char state_password = 0; /* Found a password keyword */
- int state_our_login = TRUE; /* With specific_login, found *our* login
- name (or login-less line) */
+ enum found_state keyword = NONE;
+ unsigned char found = 0; /* login + password found bits, as they can come in
+ any order */
+ bool our_login = FALSE; /* found our login name */
DEBUGASSERT(netrcfile);
+ DEBUGASSERT(!*passwordp);
file = fopen(netrcfile, FOPEN_READTEXT);
if(file) {
continue;
}
tok = netrcbuffer;
- while(tok) {
+ while(tok && !done) {
while(ISBLANK(*tok))
tok++;
/* tok is first non-space letter */
}
}
- if((login && *login) && (password && *password)) {
- done = TRUE;
- break;
- }
-
switch(state) {
case NOTHING:
if(strcasecompare("macdef", tok)) {
after this we need to search for 'login' and
'password'. */
state = HOSTFOUND;
+ keyword = NONE;
+ found = 0;
+ our_login = FALSE;
+ Curl_safefree(password);
+ if(!specific_login)
+ Curl_safefree(login);
}
else if(strcasecompare("default", tok)) {
state = HOSTVALID;
break;
case HOSTVALID:
/* we are now parsing sub-keywords concerning "our" host */
- if(state_login) {
+ if(keyword == LOGIN) {
if(specific_login) {
- state_our_login = !Curl_timestrcmp(login, tok);
+ our_login = !Curl_timestrcmp(login, tok);
}
- else if(!login || Curl_timestrcmp(login, tok)) {
- if(login_alloc) {
- free(login);
- login_alloc = FALSE;
- }
+ else {
+ our_login = TRUE;
+ free(login);
login = strdup(tok);
if(!login) {
retcode = NETRC_FAILED; /* allocation failed */
goto out;
}
- login_alloc = TRUE;
}
- state_login = 0;
+ found |= FOUND_LOGIN;
+ keyword = NONE;
}
- else if(state_password) {
- if((state_our_login || !specific_login)
- && (!password || Curl_timestrcmp(password, tok))) {
- if(password_alloc) {
- free(password);
- password_alloc = FALSE;
- }
- password = strdup(tok);
- if(!password) {
- retcode = NETRC_FAILED; /* allocation failed */
- goto out;
- }
- password_alloc = TRUE;
+ else if(keyword == PASSWORD) {
+ free(password);
+ password = strdup(tok);
+ if(!password) {
+ retcode = NETRC_FAILED; /* allocation failed */
+ goto out;
}
- state_password = 0;
+ found |= FOUND_PASSWORD;
+ keyword = NONE;
}
else if(strcasecompare("login", tok))
- state_login = 1;
+ keyword = LOGIN;
else if(strcasecompare("password", tok))
- state_password = 1;
+ keyword = PASSWORD;
else if(strcasecompare("machine", tok)) {
- /* ok, there's machine here go => */
+ /* a new machine here */
state = HOSTFOUND;
- state_our_login = FALSE;
+ keyword = NONE;
+ found = 0;
+ Curl_safefree(password);
+ if(!specific_login)
+ Curl_safefree(login);
+ }
+ else if(strcasecompare("default", tok)) {
+ state = HOSTVALID;
+ retcode = NETRC_SUCCESS; /* we did find our host */
+ Curl_safefree(password);
+ if(!specific_login)
+ Curl_safefree(login);
+ }
+ if((found == (FOUND_PASSWORD|FOUND_LOGIN)) && our_login) {
+ done = TRUE;
+ break;
}
break;
} /* switch (state) */
} /* while Curl_get_line() */
out:
+ if(!retcode && !password && our_login) {
+ /* success without a password, set a blank one */
+ password = strdup("");
+ if(!password)
+ retcode = 1; /* out of memory */
+ }
if(!retcode) {
/* success */
- if(login_alloc) {
- if(*loginp)
- free(*loginp);
+ if(!specific_login)
*loginp = login;
- }
- if(password_alloc) {
- if(*passwordp)
- free(*passwordp);
- *passwordp = password;
- }
+ *passwordp = password;
}
else {
- if(login_alloc)
+ if(!specific_login)
free(login);
- if(password_alloc)
- free(password);
+ free(password);
}
fclose(file);
}
return CURLE_OK;
}
+static bool str_has_ctrl(const char *input)
+{
+ const unsigned char *str = (const unsigned char *)input;
+ while(*str) {
+ if(*str < 0x20)
+ return TRUE;
+ str++;
+ }
+ return FALSE;
+}
+
/*
* Override the login details from the URL with that in the CURLOPT_USERPWD
* option or a .netrc file, if applicable.
if(data->state.aptr.user &&
(data->state.creds_from != CREDS_NETRC)) {
- /* there was a user name in the URL. Use the URL decoded version */
+ /* there was a username with a length in the URL. Use the URL decoded
+ version */
userp = &data->state.aptr.user;
url_provided = TRUE;
}
- ret = Curl_parsenetrc(conn->host.name,
- userp, passwdp,
- data->set.str[STRING_NETRC_FILE]);
- if(ret > 0) {
- infof(data, "Couldn't find host %s in the %s file; using defaults",
+ if(!*passwdp) {
+ ret = Curl_parsenetrc(conn->host.name,
+ userp, passwdp,
+ data->set.str[STRING_NETRC_FILE]);
+ if(ret > 0) {
+ infof(data, "Couldn't find host %s in the %s file; using defaults",
conn->host.name, data->set.str[STRING_NETRC_FILE]);
- }
- else if(ret < 0) {
- failf(data, ".netrc parser error");
- return CURLE_READ_ERROR;
- }
- else {
- /* set bits.netrc TRUE to remember that we got the name from a .netrc
- file, so that it is safe to use even if we followed a Location: to a
- different host or similar. */
- conn->bits.netrc = TRUE;
- }
- if(url_provided) {
- Curl_safefree(conn->user);
- conn->user = strdup(*userp);
- if(!conn->user)
- return CURLE_OUT_OF_MEMORY;
- }
- /* no user was set but a password, set a blank user */
- if(!*userp && *passwdp) {
- *userp = strdup("");
- if(!*userp)
- return CURLE_OUT_OF_MEMORY;
+ }
+ else if(ret < 0) {
+ failf(data, ".netrc parser error");
+ return CURLE_READ_ERROR;
+ }
+ else {
+ if(!(conn->handler->flags&PROTOPT_USERPWDCTRL)) {
+ /* if the protocol can't handle control codes in credentials, make
+ sure there are none */
+ if(str_has_ctrl(*userp) || str_has_ctrl(*passwdp)) {
+ failf(data, "control code detected in .netrc credentials");
+ return CURLE_READ_ERROR;
+ }
+ }
+ /* set bits.netrc TRUE to remember that we got the name from a .netrc
+ file, so that it is safe to use even if we followed a Location: to a
+ different host or similar. */
+ conn->bits.netrc = TRUE;
+ }
+ if(url_provided) {
+ Curl_safefree(conn->user);
+ conn->user = strdup(*userp);
+ if(!conn->user)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ /* no user was set but a password, set a blank user */
+ if(!*userp && *passwdp) {
+ *userp = strdup("");
+ if(!*userp)
+ return CURLE_OUT_OF_MEMORY;
+ }
}
}
#endif
%if bearssl
313
%endif
+# 478 and 480 are backported and do not work with this version of curl
+478
+480
\
test440 test441 test442 test443 test444 test445 test446 \
\
+test478 test479 test480 \
+\
test490 test491 test492 test493 test494 test495 test496 \
\
test500 test501 test502 test503 test504 test505 test506 test507 test508 \
--- /dev/null
+<testcase>
+<info>
+<keywords>
+netrc
+HTTP
+</keywords>
+</info>
+#
+# Server-side
+<reply>
+<data crlf="yes">
+HTTP/1.1 200 OK
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+Accept-Ranges: bytes
+Content-Length: 6
+Connection: close
+Content-Type: text/html
+Funny-head: yesyes
+
+-foo-
+</data>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+http
+</server>
+<features>
+proxy
+</features>
+<name>
+.netrc with multiple accounts for same host
+</name>
+<command>
+--netrc --netrc-file log/netrc%TESTNUMBER -x http://%HOSTIP:%HTTPPORT/ http://debbie@github.com/
+</command>
+<file name="log/netrc%TESTNUMBER" >
+
+machine github.com
+password weird
+password firstone
+login daniel
+
+machine github.com
+
+machine github.com
+login debbie
+
+machine github.com
+password weird
+password "second\r"
+login debbie
+
+</file>
+</client>
+
+<verify>
+<protocol>
+GET http://github.com/ HTTP/1.1\r
+Host: github.com\r
+Authorization: Basic %b64[debbie:second%0D]b64%\r
+User-Agent: curl/%VERSION\r
+Accept: */*\r
+Proxy-Connection: Keep-Alive\r
+\r
+</protocol>
+</verify>
+</testcase>
--- /dev/null
+<testcase>
+<info>
+<keywords>
+netrc
+HTTP
+</keywords>
+</info>
+#
+# Server-side
+<reply>
+<data crlf="yes">
+HTTP/1.1 301 Follow this you fool
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+Accept-Ranges: bytes
+Content-Length: 6
+Connection: close
+Location: http://b.com/%TESTNUMBER0002
+
+-foo-
+</data>
+
+<data2 crlf="yes">
+HTTP/1.1 200 OK
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+Accept-Ranges: bytes
+Content-Length: 7
+Connection: close
+
+target
+</data2>
+
+<datacheck crlf="yes">
+HTTP/1.1 301 Follow this you fool
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+Accept-Ranges: bytes
+Content-Length: 6
+Connection: close
+Location: http://b.com/%TESTNUMBER0002
+
+HTTP/1.1 200 OK
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+Accept-Ranges: bytes
+Content-Length: 7
+Connection: close
+
+target
+</datacheck>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+http
+</server>
+<features>
+proxy
+</features>
+<name>
+.netrc with redirect and default without password
+</name>
+<command>
+--netrc --netrc-file log/netrc%TESTNUMBER -L -x http://%HOSTIP:%HTTPPORT/ http://a.com/
+</command>
+<file name="log/netrc%TESTNUMBER" >
+
+machine a.com
+ login alice
+ password alicespassword
+
+default
+ login bob
+
+</file>
+</client>
+
+<verify>
+<protocol>
+GET http://a.com/ HTTP/1.1\r
+Host: a.com\r
+Authorization: Basic %b64[alice:alicespassword]b64%\r
+User-Agent: curl/%VERSION\r
+Accept: */*\r
+Proxy-Connection: Keep-Alive\r
+\r
+GET http://b.com/%TESTNUMBER0002 HTTP/1.1\r
+Host: b.com\r
+Authorization: Basic %b64[bob:]b64%\r
+User-Agent: curl/%VERSION\r
+Accept: */*\r
+Proxy-Connection: Keep-Alive\r
+\r
+</protocol>
+</verify>
+</testcase>
--- /dev/null
+<testcase>
+<info>
+<keywords>
+netrc
+pop3
+</keywords>
+</info>
+#
+# Server-side
+<reply>
+
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+pop3
+</server>
+<name>
+Reject .netrc with credentials using CRLF for POP3
+</name>
+<command>
+--netrc --netrc-file log/netrc%TESTNUMBER pop3://%HOSTIP:%POP3PORT/%TESTNUMBER
+</command>
+<file name="log/netrc%TESTNUMBER" >
+machine %HOSTIP
+ login alice
+ password "password\r\ncommand"
+</file>
+</client>
+
+<verify>
+<errorcode>
+26
+</errorcode>
+</verify>
+</testcase>
static CURLcode unit_setup(void)
{
- password = strdup("");
- login = strdup("");
- if(!password || !login) {
- Curl_safefree(password);
- Curl_safefree(login);
- return CURLE_OUT_OF_MEMORY;
- }
+ password = NULL;
+ login = NULL;
return CURLE_OK;
}
result = Curl_parsenetrc("test.example.com", &login, &password,
filename);
fail_unless(result == 1, "Host not found should return 1");
- abort_unless(password != NULL, "returned NULL!");
- fail_unless(password[0] == 0, "password should not have been changed");
- abort_unless(login != NULL, "returned NULL!");
- fail_unless(login[0] == 0, "login should not have been changed");
+ abort_unless(password == NULL, "password did not return NULL!");
+ abort_unless(login == NULL, "user did not return NULL!");
/*
* Test a non existent login in our netrc file.
*/
- free(login);
- login = strdup("me");
- abort_unless(login != NULL, "returned NULL!");
+ login = (char *)"me";
result = Curl_parsenetrc("example.com", &login, &password,
filename);
fail_unless(result == 0, "Host should have been found");
- abort_unless(password != NULL, "returned NULL!");
- fail_unless(password[0] == 0, "password should not have been changed");
- abort_unless(login != NULL, "returned NULL!");
- fail_unless(strncmp(login, "me", 2) == 0,
- "login should not have been changed");
+ abort_unless(password == NULL, "password is not NULL!");
/*
* Test a non existent login and host in our netrc file.
*/
- free(login);
- login = strdup("me");
- abort_unless(login != NULL, "returned NULL!");
+ login = (char *)"me";
result = Curl_parsenetrc("test.example.com", &login, &password,
filename);
fail_unless(result == 1, "Host not found should return 1");
- abort_unless(password != NULL, "returned NULL!");
- fail_unless(password[0] == 0, "password should not have been changed");
- abort_unless(login != NULL, "returned NULL!");
- fail_unless(strncmp(login, "me", 2) == 0,
- "login should not have been changed");
+ abort_unless(password == NULL, "password is not NULL!");
/*
* Test a non existent login (substring of an existing one) in our
* netrc file.
*/
- free(login);
- login = strdup("admi");
- abort_unless(login != NULL, "returned NULL!");
+ login = (char *)"admi";
result = Curl_parsenetrc("example.com", &login, &password,
filename);
fail_unless(result == 0, "Host should have been found");
- abort_unless(password != NULL, "returned NULL!");
- fail_unless(password[0] == 0, "password should not have been changed");
- abort_unless(login != NULL, "returned NULL!");
- fail_unless(strncmp(login, "admi", 4) == 0,
- "login should not have been changed");
+ abort_unless(password == NULL, "password is not NULL!");
/*
* Test a non existent login (superstring of an existing one)
* in our netrc file.
*/
- free(login);
- login = strdup("adminn");
- abort_unless(login != NULL, "returned NULL!");
+ login = (char *)"adminn";
result = Curl_parsenetrc("example.com", &login, &password,
filename);
fail_unless(result == 0, "Host should have been found");
- abort_unless(password != NULL, "returned NULL!");
- fail_unless(password[0] == 0, "password should not have been changed");
- abort_unless(login != NULL, "returned NULL!");
- fail_unless(strncmp(login, "adminn", 6) == 0,
- "login should not have been changed");
+ abort_unless(password == NULL, "password is not NULL!");
/*
* Test for the first existing host in our netrc file
* with login[0] = 0.
*/
- free(login);
- login = strdup("");
- abort_unless(login != NULL, "returned NULL!");
+ login = NULL;
result = Curl_parsenetrc("example.com", &login, &password,
filename);
fail_unless(result == 0, "Host should have been found");
* with login[0] != 0.
*/
free(password);
- password = strdup("");
- abort_unless(password != NULL, "returned NULL!");
+ free(login);
+ password = NULL;
+ login = NULL;
result = Curl_parsenetrc("example.com", &login, &password, filename);
fail_unless(result == 0, "Host should have been found");
abort_unless(password != NULL, "returned NULL!");
* with login[0] = 0.
*/
free(password);
- password = strdup("");
- abort_unless(password != NULL, "returned NULL!");
+ password = NULL;
free(login);
- login = strdup("");
- abort_unless(login != NULL, "returned NULL!");
+ login = NULL;
result = Curl_parsenetrc("curl.example.com", &login, &password,
filename);
fail_unless(result == 0, "Host should have been found");
* with login[0] != 0.
*/
free(password);
- password = strdup("");
- abort_unless(password != NULL, "returned NULL!");
+ free(login);
+ password = NULL;
+ login = NULL;
result = Curl_parsenetrc("curl.example.com", &login, &password,
filename);
fail_unless(result == 0, "Host should have been found");