Commit 53db15ba authored by Michael Kaufmann's avatar Michael Kaufmann
Browse files

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
parent a77b640c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@ Added: 7.21.5
Mutexed: netrc
---
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,
the last one will be used.

+9 −8
Original line number Diff line number Diff line
@@ -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.

.IP CURL_NETRC_OPTIONAL
The use of your \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
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 in
the URL.
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 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.

Undefined values of the option will have this effect.
.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.
.IP CURL_NETRC_REQUIRED
This value tells the library that use of the file is required, to ignore the
information in the URL, and to search the file for the host only.
The use of the \fI~/.netrc\fP file is required, and information in the URL is
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
CURL_NETRC_IGNORED
.SH PROTOCOLS
+9 −2
Original line number Diff line number Diff line
@@ -53,6 +53,8 @@ enum host_lookup_state {
int Curl_parsenetrc(const char *host,
                    char **loginp,
                    char **passwordp,
                    bool *login_changed,
                    bool *password_changed,
                    char *netrcfile)
{
  FILE *file;
@@ -164,7 +166,7 @@ int Curl_parsenetrc(const char *host,
            if(specific_login) {
              state_our_login = strcasecompare(login, tok);
            }
            else {
            else if(!login || strcmp(login, tok)) {
              if(login_alloc) {
                free(login);
                login_alloc = FALSE;
@@ -179,7 +181,8 @@ int Curl_parsenetrc(const char *host,
            state_login = 0;
          }
          else if(state_password) {
            if(state_our_login || !specific_login) {
            if((state_our_login || !specific_login)
                && (!password || strcmp(password, tok))) {
              if(password_alloc) {
                free(password);
                password_alloc = FALSE;
@@ -211,15 +214,19 @@ int Curl_parsenetrc(const char *host,

    out:
    if(!retcode) {
      *login_changed = FALSE;
      *password_changed = FALSE;
      if(login_alloc) {
        if(*loginp)
          free(*loginp);
        *loginp = login;
        *login_changed = TRUE;
      }
      if(password_alloc) {
        if(*passwordp)
          free(*passwordp);
        *passwordp = password;
        *password_changed = TRUE;
      }
    }
    else {
+2 −0
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@
int Curl_parsenetrc(const char *host,
                    char **loginp,
                    char **passwordp,
                    bool *login_changed,
                    bool *password_changed,
                    char *filename);
  /* Assume: (*passwordp)[0]=0, host[0] != 0.
   * If (*loginp)[0] = 0, search for login and password within a machine
+24 −31
Original line number Diff line number Diff line
@@ -2999,6 +2999,20 @@ static CURLcode override_login(struct Curl_easy *data,
  bool user_changed = FALSE;
  bool passwd_changed = FALSE;
  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]) {
    free(*userp);
    *userp = strdup(data->set.str[STRING_USERNAME]);
@@ -3025,16 +3039,15 @@ static CURLcode override_login(struct Curl_easy *data,
  }

  conn->bits.netrc = FALSE;
  if(data->set.use_netrc != CURL_NETRC_IGNORED) {
    char *nuser = NULL;
    char *npasswd = NULL;
  if(data->set.use_netrc != CURL_NETRC_IGNORED &&
      (!*userp || !**userp || !*passwdp || !**passwdp)) {
    bool netrc_user_changed = FALSE;
    bool netrc_passwd_changed = FALSE;
    int ret;

    if(data->set.use_netrc == CURL_NETRC_OPTIONAL)
      nuser = *userp; /* to separate otherwise identical machines */

    ret = Curl_parsenetrc(conn->host.name,
                          &nuser, &npasswd,
                          userp, passwdp,
                          &netrc_user_changed, &netrc_passwd_changed,
                          data->set.str[STRING_NETRC_FILE]);
    if(ret > 0) {
      infof(data, "Couldn't find host %s in the "
@@ -3051,34 +3064,14 @@ static CURLcode override_login(struct Curl_easy *data,
      conn->bits.netrc = TRUE;
      conn->bits.user_passwd = TRUE; /* enable user+password */

      if(data->set.use_netrc == CURL_NETRC_OPTIONAL) {
        /* prefer credentials outside netrc */
        if(nuser && !*userp) {
          free(*userp);
          *userp = nuser;
      if(netrc_user_changed) {
        user_changed = TRUE;
      }
        if(npasswd && !*passwdp) {
          free(*passwdp);
          *passwdp = npasswd;
          passwd_changed = TRUE;
        }
      }
      else {
        /* prefer netrc credentials */
        if(nuser) {
          free(*userp);
          *userp = nuser;
          user_changed = TRUE;
        }
        if(npasswd) {
          free(*passwdp);
          *passwdp = npasswd;
      if(netrc_passwd_changed) {
        passwd_changed = TRUE;
      }
    }
  }
  }

  /* for updated strings, we update them in the URL */
  if(user_changed) {
Loading