netrc: support quoted strings

The .netrc parser now accepts strings within double-quotes in order to
deal with for example passwords containing white space - which
previously was not possible.

A password that starts with a double-quote also ends with one, and
double-quotes themselves are escaped with backslashes, like \". It also
supports \n, \r and \t for newline, carriage return and tabs
respectively.

If the password does not start with a double quote, it will end at first
white space and no escaping is performed.

WARNING: this change is not entirely backwards compatible. If anyone
previously used a double-quote as the first letter of their password,
the parser will now get it differently compared to before. This is
highly unfortunate but hard to avoid.

Reported-by: ImpatientHippo on GitHub
Fixes #8908
Closes #8937
This commit is contained in:
Daniel Stenberg 2022-05-31 09:04:56 +02:00
parent b1f8d50a92
commit eeaae10c0f
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
2 changed files with 66 additions and 10 deletions

View File

@ -78,24 +78,80 @@ static int parsenetrc(const char *host,
file = fopen(netrcfile, FOPEN_READTEXT);
if(file) {
char *tok;
char *tok_buf;
bool done = FALSE;
char netrcbuffer[4096];
int netrcbuffsize = (int)sizeof(netrcbuffer);
while(!done && fgets(netrcbuffer, netrcbuffsize, file)) {
char *tok;
char *tok_end;
bool quoted;
if(state == MACDEF) {
if((netrcbuffer[0] == '\n') || (netrcbuffer[0] == '\r'))
state = NOTHING;
else
continue;
}
tok = strtok_r(netrcbuffer, " \t\n", &tok_buf);
if(tok && *tok == '#')
/* treat an initial hash as a comment line */
continue;
tok = netrcbuffer;
while(tok) {
while(ISSPACE(*tok))
tok++;
/* tok is first non-space letter */
if(!*tok || (*tok == '#'))
/* end of line or the rest is a comment */
break;
/* leading double-quote means quoted string */
quoted = (*tok == '\"');
tok_end = tok;
if(!quoted) {
while(!ISSPACE(*tok_end))
tok_end++;
*tok_end = 0;
}
else {
bool escape = FALSE;
bool endquote = FALSE;
char *store = tok;
tok_end++; /* pass the leading quote */
while(*tok_end) {
char s = *tok_end;
if(escape) {
escape = FALSE;
switch(s) {
case 'n':
s = '\n';
break;
case 'r':
s = '\r';
break;
case 't':
s = '\t';
break;
}
}
else if(s == '\\') {
escape = TRUE;
tok_end++;
continue;
}
else if(s == '\"') {
tok_end++; /* pass the ending quote */
endquote = TRUE;
break;
}
*store++ = s;
tok_end++;
}
*store = 0;
if(escape || !endquote) {
/* bad syntax, get out */
retcode = NETRC_FAILED;
goto out;
}
}
if((login && *login) && (password && *password)) {
done = TRUE;
break;
@ -183,9 +239,8 @@ static int parsenetrc(const char *host,
}
break;
} /* switch (state) */
tok = strtok_r(NULL, " \t\n", &tok_buf);
} /* while(tok) */
tok = ++tok_end;
}
} /* while fgets() */
out:

View File

@ -3011,7 +3011,8 @@ static CURLcode override_login(struct Curl_easy *data,
conn->host.name, data->set.str[STRING_NETRC_FILE]);
}
else if(ret < 0) {
return CURLE_OUT_OF_MEMORY;
failf(data, ".netrc parser error");
return CURLE_READ_ERROR;
}
else {
/* set bits.netrc TRUE to remember that we got the name from a .netrc