mirror of
https://github.com/moparisthebest/curl
synced 2025-02-28 17:31:46 -05:00
netrc: don't ignore the login name specified with "--user"
- for "--netrc", don't ignore the login/password specified with "--user", only ignore the login/password in the URL. This restores the netrc behaviour of curl 7.61.1 and earlier. - fix the documentation of CURL_NETRC_REQUIRED - improve the detection of login/password changes when reading .netrc - don't read .netrc if both login and password are already set Fixes #3213 Closes #3224
This commit is contained in:
parent
a77b640cc0
commit
53db15ba55
@ -5,7 +5,7 @@ Added: 7.21.5
|
|||||||
Mutexed: netrc
|
Mutexed: netrc
|
||||||
---
|
---
|
||||||
This option is similar to --netrc, except that you provide the path (absolute
|
This option is similar to --netrc, except that you provide the path (absolute
|
||||||
or relative) to the netrc file that Curl should use. You can only specify one
|
or relative) to the netrc file that curl should use. You can only specify one
|
||||||
netrc file per invocation. If several --netrc-file options are provided,
|
netrc file per invocation. If several --netrc-file options are provided,
|
||||||
the last one will be used.
|
the last one will be used.
|
||||||
|
|
||||||
|
@ -47,20 +47,21 @@ standard Unix ftp client does). It should only be readable by user.
|
|||||||
\fIlevel\fP should be set to one of the values described below.
|
\fIlevel\fP should be set to one of the values described below.
|
||||||
|
|
||||||
.IP CURL_NETRC_OPTIONAL
|
.IP CURL_NETRC_OPTIONAL
|
||||||
The use of your \fI~/.netrc\fP file is optional, and information in the URL is
|
The use of the \fI~/.netrc\fP file is optional, and information in the URL is
|
||||||
to be preferred. The file will be scanned for the host and user name (to
|
to be preferred. The file will be scanned for the host and user name (to find
|
||||||
find the password only) or for the host only, to find the first user name and
|
the password only) or for the host only, to find the first user name and
|
||||||
password after that \fImachine\fP, which ever information is not specified in
|
password after that \fImachine\fP, which ever information is not specified.
|
||||||
the URL.
|
|
||||||
|
|
||||||
Undefined values of the option will have this effect.
|
Undefined values of the option will have this effect.
|
||||||
.IP CURL_NETRC_IGNORED
|
.IP CURL_NETRC_IGNORED
|
||||||
The library will ignore the file and use only the information in the URL.
|
The library will ignore the \fI~/.netrc\fP file.
|
||||||
|
|
||||||
This is the default.
|
This is the default.
|
||||||
.IP CURL_NETRC_REQUIRED
|
.IP CURL_NETRC_REQUIRED
|
||||||
This value tells the library that use of the file is required, to ignore the
|
The use of the \fI~/.netrc\fP file is required, and information in the URL is
|
||||||
information in the URL, and to search the file for the host only.
|
to be ignored. The file will be scanned for the host and user name (to find
|
||||||
|
the password only) or for the host only, to find the first user name and
|
||||||
|
password after that \fImachine\fP, which ever information is not specified.
|
||||||
.SH DEFAULT
|
.SH DEFAULT
|
||||||
CURL_NETRC_IGNORED
|
CURL_NETRC_IGNORED
|
||||||
.SH PROTOCOLS
|
.SH PROTOCOLS
|
||||||
|
11
lib/netrc.c
11
lib/netrc.c
@ -53,6 +53,8 @@ enum host_lookup_state {
|
|||||||
int Curl_parsenetrc(const char *host,
|
int Curl_parsenetrc(const char *host,
|
||||||
char **loginp,
|
char **loginp,
|
||||||
char **passwordp,
|
char **passwordp,
|
||||||
|
bool *login_changed,
|
||||||
|
bool *password_changed,
|
||||||
char *netrcfile)
|
char *netrcfile)
|
||||||
{
|
{
|
||||||
FILE *file;
|
FILE *file;
|
||||||
@ -164,7 +166,7 @@ int Curl_parsenetrc(const char *host,
|
|||||||
if(specific_login) {
|
if(specific_login) {
|
||||||
state_our_login = strcasecompare(login, tok);
|
state_our_login = strcasecompare(login, tok);
|
||||||
}
|
}
|
||||||
else {
|
else if(!login || strcmp(login, tok)) {
|
||||||
if(login_alloc) {
|
if(login_alloc) {
|
||||||
free(login);
|
free(login);
|
||||||
login_alloc = FALSE;
|
login_alloc = FALSE;
|
||||||
@ -179,7 +181,8 @@ int Curl_parsenetrc(const char *host,
|
|||||||
state_login = 0;
|
state_login = 0;
|
||||||
}
|
}
|
||||||
else if(state_password) {
|
else if(state_password) {
|
||||||
if(state_our_login || !specific_login) {
|
if((state_our_login || !specific_login)
|
||||||
|
&& (!password || strcmp(password, tok))) {
|
||||||
if(password_alloc) {
|
if(password_alloc) {
|
||||||
free(password);
|
free(password);
|
||||||
password_alloc = FALSE;
|
password_alloc = FALSE;
|
||||||
@ -211,15 +214,19 @@ int Curl_parsenetrc(const char *host,
|
|||||||
|
|
||||||
out:
|
out:
|
||||||
if(!retcode) {
|
if(!retcode) {
|
||||||
|
*login_changed = FALSE;
|
||||||
|
*password_changed = FALSE;
|
||||||
if(login_alloc) {
|
if(login_alloc) {
|
||||||
if(*loginp)
|
if(*loginp)
|
||||||
free(*loginp);
|
free(*loginp);
|
||||||
*loginp = login;
|
*loginp = login;
|
||||||
|
*login_changed = TRUE;
|
||||||
}
|
}
|
||||||
if(password_alloc) {
|
if(password_alloc) {
|
||||||
if(*passwordp)
|
if(*passwordp)
|
||||||
free(*passwordp);
|
free(*passwordp);
|
||||||
*passwordp = password;
|
*passwordp = password;
|
||||||
|
*password_changed = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -26,6 +26,8 @@
|
|||||||
int Curl_parsenetrc(const char *host,
|
int Curl_parsenetrc(const char *host,
|
||||||
char **loginp,
|
char **loginp,
|
||||||
char **passwordp,
|
char **passwordp,
|
||||||
|
bool *login_changed,
|
||||||
|
bool *password_changed,
|
||||||
char *filename);
|
char *filename);
|
||||||
/* Assume: (*passwordp)[0]=0, host[0] != 0.
|
/* Assume: (*passwordp)[0]=0, host[0] != 0.
|
||||||
* If (*loginp)[0] = 0, search for login and password within a machine
|
* If (*loginp)[0] = 0, search for login and password within a machine
|
||||||
|
55
lib/url.c
55
lib/url.c
@ -2999,6 +2999,20 @@ static CURLcode override_login(struct Curl_easy *data,
|
|||||||
bool user_changed = FALSE;
|
bool user_changed = FALSE;
|
||||||
bool passwd_changed = FALSE;
|
bool passwd_changed = FALSE;
|
||||||
CURLUcode uc;
|
CURLUcode uc;
|
||||||
|
|
||||||
|
if(data->set.use_netrc == CURL_NETRC_REQUIRED && conn->bits.user_passwd) {
|
||||||
|
/* ignore user+password in the URL */
|
||||||
|
if(*userp) {
|
||||||
|
Curl_safefree(*userp);
|
||||||
|
user_changed = TRUE;
|
||||||
|
}
|
||||||
|
if(*passwdp) {
|
||||||
|
Curl_safefree(*passwdp);
|
||||||
|
passwd_changed = TRUE;
|
||||||
|
}
|
||||||
|
conn->bits.user_passwd = FALSE; /* disable user+password */
|
||||||
|
}
|
||||||
|
|
||||||
if(data->set.str[STRING_USERNAME]) {
|
if(data->set.str[STRING_USERNAME]) {
|
||||||
free(*userp);
|
free(*userp);
|
||||||
*userp = strdup(data->set.str[STRING_USERNAME]);
|
*userp = strdup(data->set.str[STRING_USERNAME]);
|
||||||
@ -3025,16 +3039,15 @@ static CURLcode override_login(struct Curl_easy *data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
conn->bits.netrc = FALSE;
|
conn->bits.netrc = FALSE;
|
||||||
if(data->set.use_netrc != CURL_NETRC_IGNORED) {
|
if(data->set.use_netrc != CURL_NETRC_IGNORED &&
|
||||||
char *nuser = NULL;
|
(!*userp || !**userp || !*passwdp || !**passwdp)) {
|
||||||
char *npasswd = NULL;
|
bool netrc_user_changed = FALSE;
|
||||||
|
bool netrc_passwd_changed = FALSE;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if(data->set.use_netrc == CURL_NETRC_OPTIONAL)
|
|
||||||
nuser = *userp; /* to separate otherwise identical machines */
|
|
||||||
|
|
||||||
ret = Curl_parsenetrc(conn->host.name,
|
ret = Curl_parsenetrc(conn->host.name,
|
||||||
&nuser, &npasswd,
|
userp, passwdp,
|
||||||
|
&netrc_user_changed, &netrc_passwd_changed,
|
||||||
data->set.str[STRING_NETRC_FILE]);
|
data->set.str[STRING_NETRC_FILE]);
|
||||||
if(ret > 0) {
|
if(ret > 0) {
|
||||||
infof(data, "Couldn't find host %s in the "
|
infof(data, "Couldn't find host %s in the "
|
||||||
@ -3051,31 +3064,11 @@ static CURLcode override_login(struct Curl_easy *data,
|
|||||||
conn->bits.netrc = TRUE;
|
conn->bits.netrc = TRUE;
|
||||||
conn->bits.user_passwd = TRUE; /* enable user+password */
|
conn->bits.user_passwd = TRUE; /* enable user+password */
|
||||||
|
|
||||||
if(data->set.use_netrc == CURL_NETRC_OPTIONAL) {
|
if(netrc_user_changed) {
|
||||||
/* prefer credentials outside netrc */
|
user_changed = TRUE;
|
||||||
if(nuser && !*userp) {
|
|
||||||
free(*userp);
|
|
||||||
*userp = nuser;
|
|
||||||
user_changed = TRUE;
|
|
||||||
}
|
|
||||||
if(npasswd && !*passwdp) {
|
|
||||||
free(*passwdp);
|
|
||||||
*passwdp = npasswd;
|
|
||||||
passwd_changed = TRUE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
if(netrc_passwd_changed) {
|
||||||
/* prefer netrc credentials */
|
passwd_changed = TRUE;
|
||||||
if(nuser) {
|
|
||||||
free(*userp);
|
|
||||||
*userp = nuser;
|
|
||||||
user_changed = TRUE;
|
|
||||||
}
|
|
||||||
if(npasswd) {
|
|
||||||
free(*passwdp);
|
|
||||||
*passwdp = npasswd;
|
|
||||||
passwd_changed = TRUE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,8 @@ static void unit_stop(void)
|
|||||||
|
|
||||||
UNITTEST_START
|
UNITTEST_START
|
||||||
int result;
|
int result;
|
||||||
|
bool login_changed;
|
||||||
|
bool password_changed;
|
||||||
|
|
||||||
static const char * const filename1 = "log/netrc1304";
|
static const char * const filename1 = "log/netrc1304";
|
||||||
memcpy(filename, filename1, strlen(filename1));
|
memcpy(filename, filename1, strlen(filename1));
|
||||||
@ -54,7 +56,8 @@ UNITTEST_START
|
|||||||
/*
|
/*
|
||||||
* Test a non existent host in our netrc file.
|
* 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,
|
||||||
|
&login_changed, &password_changed, filename);
|
||||||
fail_unless(result == 1, "Host not found should return 1");
|
fail_unless(result == 1, "Host not found should return 1");
|
||||||
abort_unless(password != NULL, "returned NULL!");
|
abort_unless(password != NULL, "returned NULL!");
|
||||||
fail_unless(password[0] == 0, "password should not have been changed");
|
fail_unless(password[0] == 0, "password should not have been changed");
|
||||||
@ -67,13 +70,16 @@ UNITTEST_START
|
|||||||
free(login);
|
free(login);
|
||||||
login = strdup("me");
|
login = strdup("me");
|
||||||
abort_unless(login != NULL, "returned NULL!");
|
abort_unless(login != NULL, "returned NULL!");
|
||||||
result = Curl_parsenetrc("example.com", &login, &password, filename);
|
result = Curl_parsenetrc("example.com", &login, &password,
|
||||||
fail_unless(result == 0, "Host should be found");
|
&login_changed, &password_changed, filename);
|
||||||
|
fail_unless(result == 0, "Host should have been found");
|
||||||
abort_unless(password != NULL, "returned NULL!");
|
abort_unless(password != NULL, "returned NULL!");
|
||||||
fail_unless(password[0] == 0, "password should not have been changed");
|
fail_unless(password[0] == 0, "password should not have been changed");
|
||||||
|
fail_unless(!password_changed, "password should not have been changed");
|
||||||
abort_unless(login != NULL, "returned NULL!");
|
abort_unless(login != NULL, "returned NULL!");
|
||||||
fail_unless(strncmp(login, "me", 2) == 0,
|
fail_unless(strncmp(login, "me", 2) == 0,
|
||||||
"login should not have been changed");
|
"login should not have been changed");
|
||||||
|
fail_unless(!login_changed, "login should not have been changed");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test a non existent login and host in our netrc file.
|
* Test a non existent login and host in our netrc file.
|
||||||
@ -81,8 +87,9 @@ UNITTEST_START
|
|||||||
free(login);
|
free(login);
|
||||||
login = strdup("me");
|
login = strdup("me");
|
||||||
abort_unless(login != NULL, "returned NULL!");
|
abort_unless(login != NULL, "returned NULL!");
|
||||||
result = Curl_parsenetrc("test.example.com", &login, &password, filename);
|
result = Curl_parsenetrc("test.example.com", &login, &password,
|
||||||
fail_unless(result == 1, "Host should be found");
|
&login_changed, &password_changed, filename);
|
||||||
|
fail_unless(result == 1, "Host not found should return 1");
|
||||||
abort_unless(password != NULL, "returned NULL!");
|
abort_unless(password != NULL, "returned NULL!");
|
||||||
fail_unless(password[0] == 0, "password should not have been changed");
|
fail_unless(password[0] == 0, "password should not have been changed");
|
||||||
abort_unless(login != NULL, "returned NULL!");
|
abort_unless(login != NULL, "returned NULL!");
|
||||||
@ -96,13 +103,16 @@ UNITTEST_START
|
|||||||
free(login);
|
free(login);
|
||||||
login = strdup("admi");
|
login = strdup("admi");
|
||||||
abort_unless(login != NULL, "returned NULL!");
|
abort_unless(login != NULL, "returned NULL!");
|
||||||
result = Curl_parsenetrc("example.com", &login, &password, filename);
|
result = Curl_parsenetrc("example.com", &login, &password,
|
||||||
fail_unless(result == 0, "Host should be found");
|
&login_changed, &password_changed, filename);
|
||||||
|
fail_unless(result == 0, "Host should have been found");
|
||||||
abort_unless(password != NULL, "returned NULL!");
|
abort_unless(password != NULL, "returned NULL!");
|
||||||
fail_unless(password[0] == 0, "password should not have been changed");
|
fail_unless(password[0] == 0, "password should not have been changed");
|
||||||
|
fail_unless(!password_changed, "password should not have been changed");
|
||||||
abort_unless(login != NULL, "returned NULL!");
|
abort_unless(login != NULL, "returned NULL!");
|
||||||
fail_unless(strncmp(login, "admi", 4) == 0,
|
fail_unless(strncmp(login, "admi", 4) == 0,
|
||||||
"login should not have been changed");
|
"login should not have been changed");
|
||||||
|
fail_unless(!login_changed, "login should not have been changed");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test a non existent login (superstring of an existing one)
|
* Test a non existent login (superstring of an existing one)
|
||||||
@ -111,13 +121,16 @@ UNITTEST_START
|
|||||||
free(login);
|
free(login);
|
||||||
login = strdup("adminn");
|
login = strdup("adminn");
|
||||||
abort_unless(login != NULL, "returned NULL!");
|
abort_unless(login != NULL, "returned NULL!");
|
||||||
result = Curl_parsenetrc("example.com", &login, &password, filename);
|
result = Curl_parsenetrc("example.com", &login, &password,
|
||||||
fail_unless(result == 0, "Host should be found");
|
&login_changed, &password_changed, filename);
|
||||||
|
fail_unless(result == 0, "Host should have been found");
|
||||||
abort_unless(password != NULL, "returned NULL!");
|
abort_unless(password != NULL, "returned NULL!");
|
||||||
fail_unless(password[0] == 0, "password should not have been changed");
|
fail_unless(password[0] == 0, "password should not have been changed");
|
||||||
|
fail_unless(!password_changed, "password should not have been changed");
|
||||||
abort_unless(login != NULL, "returned NULL!");
|
abort_unless(login != NULL, "returned NULL!");
|
||||||
fail_unless(strncmp(login, "adminn", 6) == 0,
|
fail_unless(strncmp(login, "adminn", 6) == 0,
|
||||||
"login should not have been changed");
|
"login should not have been changed");
|
||||||
|
fail_unless(!login_changed, "login should not have been changed");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test for the first existing host in our netrc file
|
* Test for the first existing host in our netrc file
|
||||||
@ -126,13 +139,16 @@ UNITTEST_START
|
|||||||
free(login);
|
free(login);
|
||||||
login = strdup("");
|
login = strdup("");
|
||||||
abort_unless(login != NULL, "returned NULL!");
|
abort_unless(login != NULL, "returned NULL!");
|
||||||
result = Curl_parsenetrc("example.com", &login, &password, filename);
|
result = Curl_parsenetrc("example.com", &login, &password,
|
||||||
|
&login_changed, &password_changed, filename);
|
||||||
fail_unless(result == 0, "Host should have been found");
|
fail_unless(result == 0, "Host should have been found");
|
||||||
abort_unless(password != NULL, "returned NULL!");
|
abort_unless(password != NULL, "returned NULL!");
|
||||||
fail_unless(strncmp(password, "passwd", 6) == 0,
|
fail_unless(strncmp(password, "passwd", 6) == 0,
|
||||||
"password should be 'passwd'");
|
"password should be 'passwd'");
|
||||||
|
fail_unless(password_changed, "password should have been changed");
|
||||||
abort_unless(login != NULL, "returned NULL!");
|
abort_unless(login != NULL, "returned NULL!");
|
||||||
fail_unless(strncmp(login, "admin", 5) == 0, "login should be 'admin'");
|
fail_unless(strncmp(login, "admin", 5) == 0, "login should be 'admin'");
|
||||||
|
fail_unless(login_changed, "login should have been changed");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test for the first existing host in our netrc file
|
* Test for the first existing host in our netrc file
|
||||||
@ -141,13 +157,16 @@ UNITTEST_START
|
|||||||
free(password);
|
free(password);
|
||||||
password = strdup("");
|
password = strdup("");
|
||||||
abort_unless(password != NULL, "returned NULL!");
|
abort_unless(password != NULL, "returned NULL!");
|
||||||
result = Curl_parsenetrc("example.com", &login, &password, filename);
|
result = Curl_parsenetrc("example.com", &login, &password,
|
||||||
|
&login_changed, &password_changed, filename);
|
||||||
fail_unless(result == 0, "Host should have been found");
|
fail_unless(result == 0, "Host should have been found");
|
||||||
abort_unless(password != NULL, "returned NULL!");
|
abort_unless(password != NULL, "returned NULL!");
|
||||||
fail_unless(strncmp(password, "passwd", 6) == 0,
|
fail_unless(strncmp(password, "passwd", 6) == 0,
|
||||||
"password should be 'passwd'");
|
"password should be 'passwd'");
|
||||||
|
fail_unless(password_changed, "password should have been changed");
|
||||||
abort_unless(login != NULL, "returned NULL!");
|
abort_unless(login != NULL, "returned NULL!");
|
||||||
fail_unless(strncmp(login, "admin", 5) == 0, "login should be 'admin'");
|
fail_unless(strncmp(login, "admin", 5) == 0, "login should be 'admin'");
|
||||||
|
fail_unless(!login_changed, "login should not have been changed");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test for the second existing host in our netrc file
|
* Test for the second existing host in our netrc file
|
||||||
@ -159,13 +178,16 @@ UNITTEST_START
|
|||||||
free(login);
|
free(login);
|
||||||
login = strdup("");
|
login = strdup("");
|
||||||
abort_unless(login != NULL, "returned NULL!");
|
abort_unless(login != NULL, "returned NULL!");
|
||||||
result = Curl_parsenetrc("curl.example.com", &login, &password, filename);
|
result = Curl_parsenetrc("curl.example.com", &login, &password,
|
||||||
|
&login_changed, &password_changed, filename);
|
||||||
fail_unless(result == 0, "Host should have been found");
|
fail_unless(result == 0, "Host should have been found");
|
||||||
abort_unless(password != NULL, "returned NULL!");
|
abort_unless(password != NULL, "returned NULL!");
|
||||||
fail_unless(strncmp(password, "none", 4) == 0,
|
fail_unless(strncmp(password, "none", 4) == 0,
|
||||||
"password should be 'none'");
|
"password should be 'none'");
|
||||||
|
fail_unless(password_changed, "password should have been changed");
|
||||||
abort_unless(login != NULL, "returned NULL!");
|
abort_unless(login != NULL, "returned NULL!");
|
||||||
fail_unless(strncmp(login, "none", 4) == 0, "login should be 'none'");
|
fail_unless(strncmp(login, "none", 4) == 0, "login should be 'none'");
|
||||||
|
fail_unless(login_changed, "login should have been changed");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test for the second existing host in our netrc file
|
* Test for the second existing host in our netrc file
|
||||||
@ -174,13 +196,16 @@ UNITTEST_START
|
|||||||
free(password);
|
free(password);
|
||||||
password = strdup("");
|
password = strdup("");
|
||||||
abort_unless(password != NULL, "returned NULL!");
|
abort_unless(password != NULL, "returned NULL!");
|
||||||
result = Curl_parsenetrc("curl.example.com", &login, &password, filename);
|
result = Curl_parsenetrc("curl.example.com", &login, &password,
|
||||||
|
&login_changed, &password_changed, filename);
|
||||||
fail_unless(result == 0, "Host should have been found");
|
fail_unless(result == 0, "Host should have been found");
|
||||||
abort_unless(password != NULL, "returned NULL!");
|
abort_unless(password != NULL, "returned NULL!");
|
||||||
fail_unless(strncmp(password, "none", 4) == 0,
|
fail_unless(strncmp(password, "none", 4) == 0,
|
||||||
"password should be 'none'");
|
"password should be 'none'");
|
||||||
|
fail_unless(password_changed, "password should have been changed");
|
||||||
abort_unless(login != NULL, "returned NULL!");
|
abort_unless(login != NULL, "returned NULL!");
|
||||||
fail_unless(strncmp(login, "none", 4) == 0, "login should be 'none'");
|
fail_unless(strncmp(login, "none", 4) == 0, "login should be 'none'");
|
||||||
|
fail_unless(!login_changed, "login should not have been changed");
|
||||||
|
|
||||||
/* TODO:
|
/* TODO:
|
||||||
* Test over the size limit password / login!
|
* Test over the size limit password / login!
|
||||||
|
Loading…
x
Reference in New Issue
Block a user