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

This commit is contained in:
Daniel Stenberg 2002-05-21 22:17:19 +00:00
Родитель c759d8427a
Коммит 105ec79b2b
5 изменённых файлов: 219 добавлений и 140 удалений

Просмотреть файл

@ -49,7 +49,9 @@
struct memdebug { struct memdebug {
int size; 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; FILE *file;
char netrcbuffer[256]; char netrcbuffer[256];
int retcode=1; int retcode=1;
int specific_login = (login[0] != 0);
char *home = NULL; char *home = NULL;
int state=NOTHING; int state=NOTHING;
char state_login=0; char state_login=0; /* Found a login keyword */
char state_password=0; 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" #define NETRC DOT_CHAR "netrc"
@ -116,6 +119,30 @@ int Curl_parsenetrc(char *host,
sprintf(netrcbuffer, "%s%s%s", home, DIR_CHAR, NETRC); 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"); file = fopen(netrcbuffer, "r");
if(file) { if(file) {
char *tok; char *tok;
@ -123,6 +150,10 @@ int Curl_parsenetrc(char *host,
while(fgets(netrcbuffer, sizeof(netrcbuffer), file)) { while(fgets(netrcbuffer, sizeof(netrcbuffer), file)) {
tok=strtok_r(netrcbuffer, " \t\n", &tok_buf); tok=strtok_r(netrcbuffer, " \t\n", &tok_buf);
while(tok) { while(tok) {
if (login[0] && password[0])
goto done;
switch(state) { switch(state) {
case NOTHING: case NOTHING:
if(strequal("machine", tok)) { if(strequal("machine", tok)) {
@ -149,17 +180,23 @@ int Curl_parsenetrc(char *host,
case HOSTVALID: case HOSTVALID:
/* we are now parsing sub-keywords concerning "our" host */ /* we are now parsing sub-keywords concerning "our" host */
if(state_login) { 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 #ifdef _NETRC_DEBUG
printf("LOGIN: %s\n", login); printf("LOGIN: %s\n", login);
#endif #endif
}
state_login=0; state_login=0;
} }
else if(state_password) { else if(state_password) {
strncpy(password, tok, PASSWORDSIZE-1); if (state_our_login || !specific_login) {
strncpy(password, tok, PASSWORDSIZE-1);
#ifdef _NETRC_DEBUG #ifdef _NETRC_DEBUG
printf("PASSWORD: %s\n", password); printf("PASSWORD: %s\n", password);
#endif #endif
}
state_password=0; state_password=0;
} }
else if(strequal("login", tok)) else if(strequal("login", tok))
@ -169,13 +206,16 @@ int Curl_parsenetrc(char *host,
else if(strequal("machine", tok)) { else if(strequal("machine", tok)) {
/* ok, there's machine here go => */ /* ok, there's machine here go => */
state = HOSTFOUND; state = HOSTFOUND;
state_our_login = 0;
} }
break; break;
} /* switch (state) */ } /* switch (state) */
tok = strtok_r(NULL, " \t\n", &tok_buf); tok = strtok_r(NULL, " \t\n", &tok_buf);
} /* while (tok) */ } /* while (tok) */
} /* while fgets() */ } /* while fgets() */
done:
fclose(file); fclose(file);
} }

Просмотреть файл

@ -25,4 +25,9 @@
int Curl_parsenetrc(char *host, int Curl_parsenetrc(char *host,
char *login, char *login,
char *password); 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 #endif

295
lib/url.c
Просмотреть файл

@ -441,7 +441,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
/* /*
* Parse the $HOME/.netrc file * Parse the $HOME/.netrc file
*/ */
data->set.use_netrc = va_arg(param, long)?TRUE:FALSE; data->set.use_netrc = va_arg(param, long);
break; break;
case CURLOPT_FOLLOWLOCATION: case CURLOPT_FOLLOWLOCATION:
/* /*
@ -1351,7 +1351,6 @@ static CURLcode CreateConnection(struct SessionHandle *data,
char resumerange[40]=""; char resumerange[40]="";
struct connectdata *conn; struct connectdata *conn;
struct connectdata *conn_temp; struct connectdata *conn_temp;
char endbracket;
int urllen; int urllen;
Curl_addrinfo *hostaddr; Curl_addrinfo *hostaddr;
#ifdef HAVE_ALARM #ifdef HAVE_ALARM
@ -1406,7 +1405,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
connections, so we set this to force-close. Protocols that support connections, so we set this to force-close. Protocols that support
this need to set this to FALSE in their "curl_do" functions. */ this need to set this to FALSE in their "curl_do" functions. */
conn->bits.close = TRUE; conn->bits.close = TRUE;
/* inherite initial knowledge from the data struct */ /* inherite initial knowledge from the data struct */
conn->bits.user_passwd = data->set.userpwd?1:0; conn->bits.user_passwd = data->set.userpwd?1:0;
conn->bits.proxy_user_passwd = data->set.proxyuserpwd?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 */ buf = data->state.buffer; /* this is our buffer */
/************************************************************* /*
* Take care of user and password authentication stuff * So if the URL was A://B/C,
*************************************************************/ * conn->protostr is A
* conn->gname is B
if(conn->bits.user_passwd && !data->set.use_netrc) { * conn->path is /C
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;
}
}
}
/************************************************************* /*************************************************************
* Take care of proxy authentication stuff * Take care of proxy authentication stuff
@ -1843,7 +1819,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
} }
if(type) { if(type) {
char command; char command;
*type=0; *type=0; /* it was in the middle of the hostname */
command = toupper(type[6]); command = toupper(type[6]);
switch(command) { switch(command) {
case 'A': /* ASCII mode */ case 'A': /* ASCII mode */
@ -1911,86 +1887,6 @@ static CURLcode CreateConnection(struct SessionHandle *data,
return CURLE_UNSUPPORTED_PROTOCOL; 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 * 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 * To be able to detect port number flawlessly, we must not confuse them
* IPv6-specified addresses in the [0::1] style. (RFC2732) * 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)) && tmp = strrchr(conn->name, ':');
(']' == 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 = strchr(conn->name, ']');
*tmp = 0; /* zero terminate */
tmp++; /* pass the ending bracket */
if(':' != *tmp)
tmp = NULL; /* no port number available */
}
else {
/* traditional IPv4-style port-extracting */
tmp = strchr(conn->name, ':');
}
if (tmp) { if (tmp) {
*tmp++ = '\0'; /* cut off the name there */ char *rest;
conn->remote_port = atoi(tmp); unsigned long port;
port=strtoul(tmp+1, &rest, 10); /* Port number must be decimal */
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) { if(data->change.proxy) {
@ -2075,6 +1974,138 @@ static CURLcode CreateConnection(struct SessionHandle *data,
free(proxydup); /* free the duplicate pointer and not the modified */ 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 * Check the current list of connections to see if we can
* re-use an already existing one or if we have to create a * re-use an already existing one or if we have to create a

Просмотреть файл

@ -650,7 +650,8 @@ struct UserDefined {
bool no_body; bool no_body;
bool set_port; bool set_port;
bool upload; bool upload;
bool use_netrc; enum CURL_NETRC_OPTION
use_netrc; /* defined in include/curl.h */
bool verbose; bool verbose;
bool krb4; /* kerberos4 connection requested */ bool krb4; /* kerberos4 connection requested */
bool reuse_forbid; /* forbidden to be reused, close after use */ bool reuse_forbid; /* forbidden to be reused, close after use */