Skip to content
Snippets Groups Projects
Commit 105ec79b authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

James Cone's efforts to add another netrc parsing "mode"

parent c759d842
No related branches found
No related tags found
No related merge requests found
......@@ -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 :-( */
};
/*
......
......@@ -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);
}
......
......@@ -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
......@@ -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 */
......@@ -1911,86 +1887,6 @@ static CURLcode CreateConnection(struct SessionHandle *data,
return CURLE_UNSUPPORTED_PROTOCOL;
}
/*************************************************************
* .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
*
......@@ -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) {
......@@ -2075,6 +1974,138 @@ static CURLcode CreateConnection(struct SessionHandle *data,
free(proxydup); /* free the duplicate pointer and not the modified */
}
/*************************************************************
* 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
......
......@@ -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 */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment