diff --git a/lib/netrc.c b/lib/netrc.c index 7ad81ece22..ba6708991d 100644 --- a/lib/netrc.c +++ b/lib/netrc.c @@ -59,23 +59,26 @@ enum found_state { #define FOUND_LOGIN 1 #define FOUND_PASSWORD 2 -#define NETRC_FILE_MISSING 1 -#define NETRC_FAILED -1 -#define NETRC_SUCCESS 0 - #define MAX_NETRC_LINE 16384 #define MAX_NETRC_FILE (128*1024) #define MAX_NETRC_TOKEN 4096 -static CURLcode file2memory(const char *filename, struct dynbuf *filebuf) +/* convert a dynbuf call CURLcode error to a NETRCcode error */ +#define curl2netrc(result) \ + (((result) == CURLE_OUT_OF_MEMORY) ? \ + NETRC_OUT_OF_MEMORY : NETRC_SYNTAX_ERROR) + +static NETRCcode file2memory(const char *filename, struct dynbuf *filebuf) { - CURLcode result = CURLE_OK; + NETRCcode ret = NETRC_FILE_MISSING; /* if it cannot open the file */ FILE *file = fopen(filename, FOPEN_READTEXT); struct dynbuf linebuf; Curl_dyn_init(&linebuf, MAX_NETRC_LINE); if(file) { + ret = NETRC_OK; while(Curl_get_line(&linebuf, file)) { + CURLcode result; const char *line = Curl_dyn_ptr(&linebuf); /* skip comments on load */ while(ISBLANK(*line)) @@ -83,27 +86,29 @@ static CURLcode file2memory(const char *filename, struct dynbuf *filebuf) if(*line == '#') continue; result = Curl_dyn_add(filebuf, line); - if(result) + if(result) { + ret = curl2netrc(result); goto done; + } } } done: Curl_dyn_free(&linebuf); if(file) fclose(file); - return result; + return ret; } /* * Returns zero on success. */ -static int parsenetrc(struct store_netrc *store, - const char *host, - char **loginp, /* might point to a username */ - char **passwordp, - const char *netrcfile) +static NETRCcode parsenetrc(struct store_netrc *store, + const char *host, + char **loginp, /* might point to a username */ + char **passwordp, + const char *netrcfile) { - int retcode = NETRC_FILE_MISSING; + NETRCcode retcode = NETRC_NO_MATCH; char *login = *loginp; char *password = NULL; bool specific_login = !!login; /* points to something */ @@ -120,8 +125,9 @@ static int parsenetrc(struct store_netrc *store, Curl_dyn_init(&token, MAX_NETRC_TOKEN); if(!store->loaded) { - if(file2memory(netrcfile, filebuf)) - return NETRC_FAILED; + NETRCcode ret = file2memory(netrcfile, filebuf); + if(ret) + return ret; store->loaded = TRUE; } @@ -151,12 +157,18 @@ static int parsenetrc(struct store_netrc *store, tok_end = tok; if(!quoted) { size_t len = 0; + CURLcode result; while(!ISSPACE(*tok_end)) { tok_end++; len++; } - if(!len || Curl_dyn_addn(&token, tok, len)) { - retcode = NETRC_FAILED; + if(!len) { + retcode = NETRC_SYNTAX_ERROR; + goto out; + } + result = Curl_dyn_addn(&token, tok, len); + if(result) { + retcode = curl2netrc(result); goto out; } } @@ -165,6 +177,7 @@ static int parsenetrc(struct store_netrc *store, bool endquote = FALSE; tok_end++; /* pass the leading quote */ while(*tok_end) { + CURLcode result; char s = *tok_end; if(escape) { escape = FALSE; @@ -190,15 +203,16 @@ static int parsenetrc(struct store_netrc *store, endquote = TRUE; break; } - if(Curl_dyn_addn(&token, &s, 1)) { - retcode = NETRC_FAILED; + result = Curl_dyn_addn(&token, &s, 1); + if(result) { + retcode = curl2netrc(result); goto out; } tok_end++; } if(escape || !endquote) { /* bad syntax, get out */ - retcode = NETRC_FAILED; + retcode = NETRC_SYNTAX_ERROR; goto out; } } @@ -226,7 +240,7 @@ static int parsenetrc(struct store_netrc *store, } else if(strcasecompare("default", tok)) { state = HOSTVALID; - retcode = NETRC_SUCCESS; /* we did find our host */ + retcode = NETRC_OK; /* we did find our host */ } break; case MACDEF: @@ -237,7 +251,7 @@ static int parsenetrc(struct store_netrc *store, if(strcasecompare(host, tok)) { /* and yes, this is our host! */ state = HOSTVALID; - retcode = NETRC_SUCCESS; /* we did find our host */ + retcode = NETRC_OK; /* we did find our host */ } else /* not our host */ @@ -253,7 +267,7 @@ static int parsenetrc(struct store_netrc *store, free(login); login = strdup(tok); if(!login) { - retcode = NETRC_FAILED; /* allocation failed */ + retcode = NETRC_OUT_OF_MEMORY; /* allocation failed */ goto out; } } @@ -264,7 +278,7 @@ static int parsenetrc(struct store_netrc *store, free(password); password = strdup(tok); if(!password) { - retcode = NETRC_FAILED; /* allocation failed */ + retcode = NETRC_OUT_OF_MEMORY; /* allocation failed */ goto out; } if(!specific_login || our_login) @@ -290,7 +304,7 @@ static int parsenetrc(struct store_netrc *store, } else if(strcasecompare("default", tok)) { state = HOSTVALID; - retcode = NETRC_SUCCESS; /* we did find our host */ + retcode = NETRC_OK; /* we did find our host */ Curl_safefree(password); if(!specific_login) Curl_safefree(login); @@ -321,11 +335,11 @@ out: /* success without a password, set a blank one */ password = strdup(""); if(!password) - retcode = 1; /* out of memory */ + retcode = NETRC_OUT_OF_MEMORY; /* out of memory */ } else if(!login && !password) /* a default with no credentials */ - retcode = NETRC_FILE_MISSING; + retcode = NETRC_NO_MATCH; } if(!retcode) { /* success */ @@ -343,17 +357,34 @@ out: return retcode; } +const char *Curl_netrc_strerror(NETRCcode ret) +{ + switch(ret) { + default: + return ""; /* not a legit error */ + case NETRC_FILE_MISSING: + return "no such file"; + case NETRC_NO_MATCH: + return "no matching entry"; + case NETRC_OUT_OF_MEMORY: + return "out of memory"; + case NETRC_SYNTAX_ERROR: + return "syntax error"; + } + /* never reached */ +} + /* * @unittest: 1304 * * *loginp and *passwordp MUST be allocated if they are not NULL when passed * in. */ -int Curl_parsenetrc(struct store_netrc *store, const char *host, - char **loginp, char **passwordp, - char *netrcfile) +NETRCcode Curl_parsenetrc(struct store_netrc *store, const char *host, + char **loginp, char **passwordp, + char *netrcfile) { - int retcode = 1; + NETRCcode retcode = NETRC_OK; char *filealloc = NULL; if(!netrcfile) { @@ -391,23 +422,23 @@ int Curl_parsenetrc(struct store_netrc *store, const char *host, } if(!home) - return retcode; /* no home directory found (or possibly out of - memory) */ + return NETRC_FILE_MISSING; /* no home directory found (or possibly out + of memory) */ filealloc = aprintf("%s%s.netrc", home, DIR_CHAR); if(!filealloc) { free(homea); - return -1; + return NETRC_OUT_OF_MEMORY; } retcode = parsenetrc(store, host, loginp, passwordp, filealloc); free(filealloc); #ifdef _WIN32 - if((retcode == NETRC_FILE_MISSING) || (retcode == NETRC_FAILED)) { + if(retcode == NETRC_FILE_MISSING) { /* fallback to the old-style "_netrc" file */ filealloc = aprintf("%s%s_netrc", home, DIR_CHAR); if(!filealloc) { free(homea); - return -1; + return NETRC_OUT_OF_MEMORY; } retcode = parsenetrc(store, host, loginp, passwordp, filealloc); free(filealloc); diff --git a/lib/netrc.h b/lib/netrc.h index 0ef9ff78ea..ac0f88622b 100644 --- a/lib/netrc.h +++ b/lib/netrc.h @@ -34,12 +34,21 @@ struct store_netrc { BIT(loaded); }; +typedef enum { + NETRC_OK, + NETRC_NO_MATCH, /* no matching entry in the file */ + NETRC_SYNTAX_ERROR, /* in the netrc file */ + NETRC_FILE_MISSING, /* the netrc file does not exist */ + NETRC_OUT_OF_MEMORY, /* while parsing netrc */ + NETRC_LAST /* never used */ +} NETRCcode; + +const char *Curl_netrc_strerror(NETRCcode ret); void Curl_netrc_init(struct store_netrc *s); void Curl_netrc_cleanup(struct store_netrc *s); -/* returns -1 on failure, 0 if the host is found, 1 is the host is not found */ -int Curl_parsenetrc(struct store_netrc *s, const char *host, char **loginp, - char **passwordp, char *filename); +NETRCcode Curl_parsenetrc(struct store_netrc *s, const char *host, + char **loginp, char **passwordp, char *filename); /* Assume: (*passwordp)[0]=0, host[0] != 0. * If (*loginp)[0] = 0, search for login and password within a machine * section in the netrc. diff --git a/lib/url.c b/lib/url.c index 0f3d1002b4..fb3f83f8b3 100644 --- a/lib/url.c +++ b/lib/url.c @@ -2690,7 +2690,6 @@ static CURLcode override_login(struct Curl_easy *data, } conn->bits.netrc = FALSE; if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) { - int ret; bool url_provided = FALSE; if(data->state.aptr.user && @@ -2702,17 +2701,19 @@ static CURLcode override_login(struct Curl_easy *data, } if(!*passwdp) { - ret = Curl_parsenetrc(&data->state.netrc, conn->host.name, - userp, passwdp, - data->set.str[STRING_NETRC_FILE]); - if(ret > 0) { + NETRCcode ret = Curl_parsenetrc(&data->state.netrc, conn->host.name, + userp, passwdp, + data->set.str[STRING_NETRC_FILE]); + if(ret && ((ret == NETRC_NO_MATCH) || + (data->set.use_netrc == CURL_NETRC_OPTIONAL))) { infof(data, "Couldn't find host %s in the %s file; using defaults", conn->host.name, (data->set.str[STRING_NETRC_FILE] ? data->set.str[STRING_NETRC_FILE] : ".netrc")); } - else if(ret < 0) { - failf(data, ".netrc parser error"); + else if(ret) { + const char *m = Curl_netrc_strerror(ret); + failf(data, ".netrc error: %s", m); return CURLE_READ_ERROR; } else { diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 1fc6c66817..65f7712f23 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -101,7 +101,7 @@ test652 test653 test654 test655 test656 test658 test659 test660 test661 \ test662 test663 test664 test665 test666 test667 test668 test669 test670 \ test671 test672 test673 test674 test675 test676 test677 test678 test679 \ test680 test681 test682 test683 test684 test685 test686 test687 test688 \ -test689 test690 test691 test692 test693 test694 test695 test696 \ +test689 test690 test691 test692 test693 test694 test695 test696 test697 \ \ test700 test701 test702 test703 test704 test705 test706 test707 test708 \ test709 test710 test711 test712 test713 test714 test715 test716 test717 \ diff --git a/tests/data/test697 b/tests/data/test697 new file mode 100644 index 0000000000..5b97761690 --- /dev/null +++ b/tests/data/test697 @@ -0,0 +1,37 @@ + + + +HTTP +netrc + + +# +# Server-side + + + +# +# Client-side + + +none + + +http + + +netrc with missing netrc file + + +--netrc --netrc-file %LOGDIR/netrc%TESTNUMBER http://user1@http.example/ + + + +# +# Verify data after the test has been "shot" + + +26 + + +