aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/memdebug.c4
-rw-r--r--lib/netrc.c52
-rw-r--r--lib/netrc.h5
-rw-r--r--lib/url.c293
-rw-r--r--lib/urldata.h3
5 files changed, 218 insertions, 139 deletions
diff --git a/lib/memdebug.c b/lib/memdebug.c
index f46d23b2a..6a9ee7bc5 100644
--- a/lib/memdebug.c
+++ b/lib/memdebug.c
@@ -49,7 +49,9 @@
struct memdebug {
int size;
- char mem[1];
+ double mem[1];
+ /* I'm hoping this is the thing with the strictest alignment
+ * requirements. That also means we waste some space :-( */
};
/*
diff --git a/lib/netrc.c b/lib/netrc.c
index 46f225511..e3b4a4aea 100644
--- a/lib/netrc.c
+++ b/lib/netrc.c
@@ -78,12 +78,15 @@ int Curl_parsenetrc(char *host,
FILE *file;
char netrcbuffer[256];
int retcode=1;
+
+ int specific_login = (login[0] != 0);
char *home = NULL;
int state=NOTHING;
- char state_login=0;
- char state_password=0;
+ char state_login=0; /* Found a login keyword */
+ char state_password=0; /* Found a password keyword */
+ char state_our_login=0; /* With specific_login, found *our* login name */
#define NETRC DOT_CHAR "netrc"
@@ -116,6 +119,30 @@ int Curl_parsenetrc(char *host,
sprintf(netrcbuffer, "%s%s%s", home, DIR_CHAR, NETRC);
+#ifdef MALLOCDEBUG
+ {
+ /* This is a hack to allow testing.
+ * If compiled with --enable-debug and CURL_DEBUG_NETRC is defined,
+ * then it's the path to a substitute .netrc for testing purposes *only* */
+
+ char *override = curl_getenv("CURL_DEBUG_NETRC");
+
+ if (override != NULL) {
+ printf("NETRC: overridden .netrc file: %s\n", home);
+
+ if (strlen(override)+1 > sizeof(netrcbuffer)) {
+ free(override);
+ if(NULL==pw)
+ free(home);
+
+ return -1;
+ }
+ strcpy(netrcbuffer, override);
+ free(override);
+ }
+ }
+#endif /* MALLOCDEBUG */
+
file = fopen(netrcbuffer, "r");
if(file) {
char *tok;
@@ -123,6 +150,10 @@ int Curl_parsenetrc(char *host,
while(fgets(netrcbuffer, sizeof(netrcbuffer), file)) {
tok=strtok_r(netrcbuffer, " \t\n", &tok_buf);
while(tok) {
+
+ if (login[0] && password[0])
+ goto done;
+
switch(state) {
case NOTHING:
if(strequal("machine", tok)) {
@@ -149,17 +180,23 @@ int Curl_parsenetrc(char *host,
case HOSTVALID:
/* we are now parsing sub-keywords concerning "our" host */
if(state_login) {
- strncpy(login, tok, LOGINSIZE-1);
+ if (specific_login) {
+ state_our_login = strequal(login, tok);
+ }else{
+ strncpy(login, tok, LOGINSIZE-1);
#ifdef _NETRC_DEBUG
- printf("LOGIN: %s\n", login);
+ printf("LOGIN: %s\n", login);
#endif
+ }
state_login=0;
}
else if(state_password) {
- strncpy(password, tok, PASSWORDSIZE-1);
+ if (state_our_login || !specific_login) {
+ strncpy(password, tok, PASSWORDSIZE-1);
#ifdef _NETRC_DEBUG
- printf("PASSWORD: %s\n", password);
+ printf("PASSWORD: %s\n", password);
#endif
+ }
state_password=0;
}
else if(strequal("login", tok))
@@ -169,13 +206,16 @@ int Curl_parsenetrc(char *host,
else if(strequal("machine", tok)) {
/* ok, there's machine here go => */
state = HOSTFOUND;
+ state_our_login = 0;
}
break;
} /* switch (state) */
+
tok = strtok_r(NULL, " \t\n", &tok_buf);
} /* while (tok) */
} /* while fgets() */
+done:
fclose(file);
}
diff --git a/lib/netrc.h b/lib/netrc.h
index 5c98571e7..4aa3c953c 100644
--- a/lib/netrc.h
+++ b/lib/netrc.h
@@ -25,4 +25,9 @@
int Curl_parsenetrc(char *host,
char *login,
char *password);
+ /* 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.
+ */
#endif
diff --git a/lib/url.c b/lib/url.c
index 4b20c131a..8ea4b7c4f 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -441,7 +441,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
/*
* Parse the $HOME/.netrc file
*/
- data->set.use_netrc = va_arg(param, long)?TRUE:FALSE;
+ data->set.use_netrc = va_arg(param, long);
break;
case CURLOPT_FOLLOWLOCATION:
/*
@@ -1351,7 +1351,6 @@ static CURLcode CreateConnection(struct SessionHandle *data,
char resumerange[40]="";
struct connectdata *conn;
struct connectdata *conn_temp;
- char endbracket;
int urllen;
Curl_addrinfo *hostaddr;
#ifdef HAVE_ALARM
@@ -1406,7 +1405,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
connections, so we set this to force-close. Protocols that support
this need to set this to FALSE in their "curl_do" functions. */
conn->bits.close = TRUE;
-
+
/* inherite initial knowledge from the data struct */
conn->bits.user_passwd = data->set.userpwd?1:0;
conn->bits.proxy_user_passwd = data->set.proxyuserpwd?1:0;
@@ -1533,35 +1532,12 @@ static CURLcode CreateConnection(struct SessionHandle *data,
buf = data->state.buffer; /* this is our buffer */
- /*************************************************************
- * Take care of user and password authentication stuff
- *************************************************************/
-
- if(conn->bits.user_passwd && !data->set.use_netrc) {
- data->state.user[0] =0;
- data->state.passwd[0]=0;
-
- if(*data->set.userpwd != ':') {
- /* the name is given, get user+password */
- sscanf(data->set.userpwd, "%127[^:]:%127[^\n]",
- data->state.user, data->state.passwd);
- }
- else
- /* no name given, get the password only */
- sscanf(data->set.userpwd+1, "%127[^\n]", data->state.passwd);
-
- /* check for password, if no ask for one */
- if( !data->state.passwd[0] ) {
- if(!data->set.fpasswd ||
- data->set.fpasswd(data->set.passwd_client,
- "password:", data->state.passwd,
- sizeof(data->state.passwd)))
- {
- failf(data, "Bad password from password callback");
- return CURLE_BAD_PASSWORD_ENTERED;
- }
- }
- }
+ /*
+ * So if the URL was A://B/C,
+ * conn->protostr is A
+ * conn->gname is B
+ * conn->path is /C
+ */
/*************************************************************
* Take care of proxy authentication stuff
@@ -1843,7 +1819,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
}
if(type) {
char command;
- *type=0;
+ *type=0; /* it was in the middle of the hostname */
command = toupper(type[6]);
switch(command) {
case 'A': /* ASCII mode */
@@ -1912,86 +1888,6 @@ static CURLcode CreateConnection(struct SessionHandle *data,
}
/*************************************************************
- * .netrc scanning coming up
- *************************************************************/
- if(data->set.use_netrc) {
- if(Curl_parsenetrc(conn->hostname,
- data->state.user,
- data->state.passwd)) {
- infof(data, "Couldn't find host %s in the .netrc file, using defaults",
- conn->hostname);
- }
- else
- conn->bits.user_passwd = 1; /* enable user+password */
-
- /* weather we failed or not, we don't know which fields that were filled
- in anyway */
- if(!data->state.user[0])
- strcpy(data->state.user, CURL_DEFAULT_USER);
- if(!data->state.passwd[0])
- strcpy(data->state.passwd, CURL_DEFAULT_PASSWORD);
- }
- else if(!(conn->bits.user_passwd) &&
- (conn->protocol & (PROT_FTP|PROT_HTTP)) ) {
- /* This is a FTP or HTTP URL, and we haven't got the user+password in
- * the extra parameter, we will now try to extract the possible
- * user+password pair in a string like:
- * ftp://user:password@ftp.my.site:8021/README */
- char *ptr=NULL; /* assign to remove possible warnings */
- if((ptr=strchr(conn->name, '@'))) {
- /* there's a user+password given here, to the left of the @ */
-
- data->state.user[0] =0;
- data->state.passwd[0]=0;
-
- if(*conn->name != ':') {
- /* the name is given, get user+password */
- sscanf(conn->name, "%127[^:@]:%127[^@]",
- data->state.user, data->state.passwd);
- }
- else
- /* no name given, get the password only */
- sscanf(conn->name+1, "%127[^@]", data->state.passwd);
-
- if(data->state.user[0]) {
- char *newname=curl_unescape(data->state.user, 0);
- if(strlen(newname) < sizeof(data->state.user)) {
- strcpy(data->state.user, newname);
- }
- /* if the new name is longer than accepted, then just use
- the unconverted name, it'll be wrong but what the heck */
- free(newname);
- }
-
- /* check for password, if no ask for one */
- if( !data->state.passwd[0] ) {
- if(!data->set.fpasswd ||
- data->set.fpasswd(data->set.passwd_client,
- "password:", data->state.passwd,
- sizeof(data->state.passwd))) {
- failf(data, "Bad password from password callback");
- return CURLE_BAD_PASSWORD_ENTERED;
- }
- }
- else {
- /* we have a password found in the URL, decode it! */
- char *newpasswd=curl_unescape(data->state.passwd, 0);
- if(strlen(newpasswd) < sizeof(data->state.passwd)) {
- strcpy(data->state.passwd, newpasswd);
- }
- free(newpasswd);
- }
-
- conn->name = ++ptr;
- conn->bits.user_passwd=TRUE; /* enable user+password */
- }
- else {
- strcpy(data->state.user, CURL_DEFAULT_USER);
- strcpy(data->state.passwd, CURL_DEFAULT_PASSWORD);
- }
- }
-
- /*************************************************************
* Figure out the remote port number
*
* No matter if we use a proxy or not, we have to figure out the remote
@@ -1999,29 +1895,32 @@ static CURLcode CreateConnection(struct SessionHandle *data,
*
* To be able to detect port number flawlessly, we must not confuse them
* IPv6-specified addresses in the [0::1] style. (RFC2732)
+ *
+ * The conn->name is currently [user:passwd@]host[:port] where host could
+ * be a hostname, IPv4 address or IPv6 address.
*************************************************************/
- if((1 == sscanf(conn->name, "[%*39[0-9a-fA-F:.]%c", &endbracket)) &&
- (']' == endbracket)) {
- /* This is a (IPv6-style) specified IP-address. We support _any_
- IP within brackets to be really generic. */
- conn->name++; /* pass the starting bracket */
+ tmp = strrchr(conn->name, ':');
- tmp = strchr(conn->name, ']');
- *tmp = 0; /* zero terminate */
+ if (tmp) {
+ char *rest;
+ unsigned long port;
- tmp++; /* pass the ending bracket */
- if(':' != *tmp)
- tmp = NULL; /* no port number available */
- }
- else {
- /* traditional IPv4-style port-extracting */
- tmp = strchr(conn->name, ':');
- }
+ port=strtoul(tmp+1, &rest, 10); /* Port number must be decimal */
- if (tmp) {
- *tmp++ = '\0'; /* cut off the name there */
- conn->remote_port = atoi(tmp);
+ if (rest != (tmp+1) && *rest == '\0') {
+ /* The colon really did have only digits after it,
+ * so it is either a port number or a mistake */
+
+ if (port > 0xffff) { /* Single unix standard says port numbers are
+ * 16 bits long */
+ failf(data, "Port number too large: %lu", port);
+ return CURLE_URL_MALFORMAT;
+ }
+
+ *tmp = '\0'; /* cut off the name there */
+ conn->remote_port = port;
+ }
}
if(data->change.proxy) {
@@ -2076,6 +1975,138 @@ static CURLcode CreateConnection(struct SessionHandle *data,
}
/*************************************************************
+ * Take care of user and password authentication stuff
+ *************************************************************/
+
+ /*
+ * Inputs: data->set.userpwd (CURLOPT_USERPWD)
+ * data->set.fpasswd (CURLOPT_PASSWDFUNCTION)
+ * data->set.use_netrc (CURLOPT_NETRC)
+ * conn->hostname
+ * netrc file
+ * hard-coded defaults
+ *
+ * Outputs: (almost :- all currently undefined)
+ * conn->bits.user_passwd - non-zero if non-default passwords exist
+ * conn->state.user - non-zero length if defined
+ * conn->state.passwd - ditto
+ * conn->hostname - remove user name and password
+ */
+
+ /* At this point, we're hoping all the other special cases have
+ * been taken care of, so conn->hostname is at most
+ * [user[:password]]@]hostname
+ *
+ * We need somewhere to put the embedded details, so do that first.
+ */
+
+ data->state.user[0] =0; /* to make everything well-defined */
+ data->state.passwd[0]=0;
+
+ if (conn->protocol & (PROT_FTP|PROT_HTTP)) {
+ /* This is a FTP or HTTP URL, we will now try to extract the possible
+ * user+password pair in a string like:
+ * ftp://user:password@ftp.my.site:8021/README */
+ char *ptr=strchr(conn->name, '@');
+ char *userpass = conn->name;
+ if(ptr != NULL) {
+ /* there's a user+password given here, to the left of the @ */
+
+ conn->name = conn->hostname = ++ptr;
+
+ /* So the hostname is sane. Only bother interpreting the
+ * results if we could care. It could still be wasted
+ * work because it might be overtaken by the programmatically
+ * set user/passwd, but doing that first adds more cases here :-(
+ */
+
+ if (data->set.use_netrc != CURL_NETRC_REQUIRED) {
+ /* We could use the one in the URL */
+
+ conn->bits.user_passwd = 1; /* enable user+password */
+
+ if(*userpass != ':') {
+ /* the name is given, get user+password */
+ sscanf(userpass, "%127[^:@]:%127[^@]",
+ data->state.user, data->state.passwd);
+ }
+ else
+ /* no name given, get the password only */
+ sscanf(userpass, ":%127[^@]", data->state.passwd);
+
+ if(data->state.user[0]) {
+ char *newname=curl_unescape(data->state.user, 0);
+ if(strlen(newname) < sizeof(data->state.user)) {
+ strcpy(data->state.user, newname);
+ }
+ /* if the new name is longer than accepted, then just use
+ the unconverted name, it'll be wrong but what the heck */
+ free(newname);
+ }
+ if (data->state.passwd[0]) {
+ /* we have a password found in the URL, decode it! */
+ char *newpasswd=curl_unescape(data->state.passwd, 0);
+ if(strlen(newpasswd) < sizeof(data->state.passwd)) {
+ strcpy(data->state.passwd, newpasswd);
+ }
+ free(newpasswd);
+ }
+ }
+ }
+ }
+
+ /* Programmatically set password:
+ * - always applies, if available
+ * - takes precedence over the values we just set above
+ * so scribble it over the top.
+ * User-supplied passwords are assumed not to need unescaping.
+ *
+ * user_password is set in "inherite initial knowledge' above,
+ * so it doesn't have to be set in this block
+ */
+ if (data->set.userpwd != NULL) {
+ if(*data->set.userpwd != ':') {
+ /* the name is given, get user+password */
+ sscanf(data->set.userpwd, "%127[^:]:%127[^\n]",
+ data->state.user, data->state.passwd);
+ }
+ else
+ /* no name given, get the password only */
+ sscanf(data->set.userpwd+1, "%127[^\n]", data->state.passwd);
+ }
+
+ if (data->set.use_netrc != CURL_NETRC_IGNORED &&
+ data->state.passwd[0] == '\0' ) { /* need passwd */
+ if(Curl_parsenetrc(conn->hostname,
+ data->state.user,
+ data->state.passwd)) {
+ infof(data, "Couldn't find host %s in the .netrc file, using defaults",
+ conn->hostname);
+ } else
+ conn->bits.user_passwd = 1; /* enable user+password */
+ }
+
+ /* if we have a user but no password, ask for one */
+ if(conn->bits.user_passwd &&
+ !data->state.passwd[0] ) {
+ if(!data->set.fpasswd ||
+ data->set.fpasswd(data->set.passwd_client,
+ "password:", data->state.passwd,
+ sizeof(data->state.passwd)))
+ return CURLE_BAD_PASSWORD_ENTERED;
+ }
+
+ /* So we could have a password but no user; that's just too bad. */
+
+ /* If our protocol needs a password and we have none, use the defaults */
+ if ( (conn->protocol & (PROT_FTP|PROT_HTTP)) &&
+ !conn->bits.user_passwd) {
+ strcpy(data->state.user, CURL_DEFAULT_USER);
+ strcpy(data->state.passwd, CURL_DEFAULT_PASSWORD);
+ /* This is the default password, so DON'T set conn->bits.user_passwd */
+ }
+
+ /*************************************************************
* Check the current list of connections to see if we can
* re-use an already existing one or if we have to create a
* new one.
diff --git a/lib/urldata.h b/lib/urldata.h
index ff2a997a0..209bf531d 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -650,7 +650,8 @@ struct UserDefined {
bool no_body;
bool set_port;
bool upload;
- bool use_netrc;
+ enum CURL_NETRC_OPTION
+ use_netrc; /* defined in include/curl.h */
bool verbose;
bool krb4; /* kerberos4 connection requested */
bool reuse_forbid; /* forbidden to be reused, close after use */