mirror of
https://github.com/curl/curl.git
synced 2026-05-20 15:16:21 +03:00
netrc: scanner refactor
Refactor the netrc scanner. Add test case for checking that the last matched machine with unmatched login does not return the password as success (unit1304). Closes #21624
This commit is contained in:
parent
5c1e017987
commit
4ae1d7cc26
4 changed files with 616 additions and 563 deletions
895
lib/netrc.c
895
lib/netrc.c
|
|
@ -36,38 +36,469 @@
|
|||
#endif
|
||||
|
||||
#include "netrc.h"
|
||||
#include "urldata.h"
|
||||
#include "creds.h"
|
||||
#include "curl_trc.h"
|
||||
#include "strcase.h"
|
||||
#include "curl_get_line.h"
|
||||
#include "curlx/fopen.h"
|
||||
#include "curlx/strparse.h"
|
||||
|
||||
/* Get user and password from .netrc when given a machine name */
|
||||
|
||||
enum host_lookup_state {
|
||||
NOTHING,
|
||||
HOSTFOUND, /* the 'machine' keyword was found */
|
||||
HOSTVALID, /* this is "our" machine! */
|
||||
MACDEF
|
||||
};
|
||||
|
||||
enum found_state {
|
||||
NONE,
|
||||
LOGIN,
|
||||
PASSWORD
|
||||
};
|
||||
|
||||
#define FOUND_LOGIN 1
|
||||
#define FOUND_PASSWORD 2
|
||||
/* .netrc is not really a standard. The GNU definition can be found here:
|
||||
* https://www.gnu.org/software/inetutils/manual/\
|
||||
* html_node/The-_002enetrc-file.html
|
||||
* This gives grammar like:
|
||||
*
|
||||
* LITERAL := \S+ | QUOTED
|
||||
* QUOTED := "(\\[rnt\]|[^"])*"
|
||||
* ANYTHING := .
|
||||
* EMPTY_LINE := \r*\n\r*\n
|
||||
* MACHINE := machine # case-insensitive
|
||||
* LOGIN := login # case-insensitive
|
||||
* PASSWD := password # case-insensitive
|
||||
* ACCOUNT := account # case-insensitive
|
||||
* MACDEF := macdef # case-insensitive
|
||||
* DEFAULT := default # case-insensitive
|
||||
*
|
||||
* MACRO := MACDEF ANYTHING* EMPTY_LINE
|
||||
* JUNK := LITERAL
|
||||
* LKEY := ( LOGIN | PASSWD | ACCOUNT ) LITERAL
|
||||
* MENTRY := MACHINE LITERAL LKEY*
|
||||
* DENTRY := DEFAULT LKEY*
|
||||
* NETRC := (MENTRY | DENTRY | MACRO | JUNK )* EOF
|
||||
*
|
||||
* Tokens are separated by whitespace or newlines. which have otherwise
|
||||
* no special meaning, apart from the empty line ending a MACRO.
|
||||
*
|
||||
* Parsing is not strict, unmatched LITERALs are ignored
|
||||
*/
|
||||
|
||||
#define MAX_NETRC_LINE 16384
|
||||
#define MAX_NETRC_FILE (128 * 1024)
|
||||
#define MAX_NETRC_TOKEN 4096
|
||||
|
||||
#define NETRC_DEBUG 0
|
||||
|
||||
/* 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)
|
||||
#define curl2netrc(r) \
|
||||
((!(r)) ? NETRC_OK : (((r) == CURLE_OUT_OF_MEMORY) ? \
|
||||
NETRC_OUT_OF_MEMORY : NETRC_SYNTAX_ERROR))
|
||||
|
||||
typedef enum {
|
||||
NETRC_TOK_EOF,
|
||||
NETRC_TOK_LITERAL,
|
||||
NETRC_TOK_MACHINE,
|
||||
NETRC_TOK_DEFAULT,
|
||||
NETRC_TOK_ACCOUNT,
|
||||
NETRC_TOK_LOGIN,
|
||||
NETRC_TOK_PASSWD,
|
||||
NETRC_TOK_MACDEF,
|
||||
NETRC_TOK_JUNK
|
||||
} curl_netrc_token;
|
||||
|
||||
struct netrc_lexer {
|
||||
struct Curl_easy *data;
|
||||
const char *content;
|
||||
const char *pos;
|
||||
struct dynbuf literal;
|
||||
curl_netrc_token token;
|
||||
bool pushed;
|
||||
};
|
||||
|
||||
#if NETRC_DEBUG
|
||||
static const char *netrc_tokenstr(curl_netrc_token token)
|
||||
{
|
||||
switch(token) {
|
||||
case NETRC_TOK_EOF:
|
||||
return "[EOF]";
|
||||
case NETRC_TOK_LITERAL:
|
||||
return "[LITERAL]";
|
||||
case NETRC_TOK_MACHINE:
|
||||
return "[MACHINE]";
|
||||
case NETRC_TOK_DEFAULT:
|
||||
return "[DEFAULT]";
|
||||
case NETRC_TOK_ACCOUNT:
|
||||
return "[ACCOUNT]";
|
||||
case NETRC_TOK_LOGIN:
|
||||
return "[LOGIN]";
|
||||
case NETRC_TOK_PASSWD:
|
||||
return "[PASSWORD]";
|
||||
case NETRC_TOK_MACDEF:
|
||||
return "[MACDEF]";
|
||||
case NETRC_TOK_JUNK:
|
||||
return "[JUNK]";
|
||||
default:
|
||||
return "[???]";
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void netrc_lexer_init(struct netrc_lexer *lexer,
|
||||
struct Curl_easy *data,
|
||||
const char *content)
|
||||
{
|
||||
curlx_dyn_init(&lexer->literal, MAX_NETRC_TOKEN);
|
||||
lexer->data = data;
|
||||
lexer->content = lexer->pos = content;
|
||||
}
|
||||
|
||||
static void netrc_lexer_cleanup(struct netrc_lexer *lexer)
|
||||
{
|
||||
lexer->content = lexer->pos = NULL;
|
||||
lexer->data = NULL;
|
||||
curlx_dyn_free(&lexer->literal);
|
||||
}
|
||||
|
||||
static void netrc_skip_blanks(struct netrc_lexer *lexer)
|
||||
{
|
||||
const char *s = lexer->pos;
|
||||
while(*s) {
|
||||
curlx_str_passblanks(&s);
|
||||
while(*s == '\r')
|
||||
++s;
|
||||
if(*s == '\n') {
|
||||
++s;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
lexer->pos = s;
|
||||
}
|
||||
|
||||
static void netrc_skip_to_empty_line(struct netrc_lexer *lexer)
|
||||
{
|
||||
const char *s = lexer->pos;
|
||||
while(*s) {
|
||||
if(*s == '\r')
|
||||
++s;
|
||||
else if(*s == '\n') {
|
||||
++s;
|
||||
while(*s == '\r')
|
||||
++s;
|
||||
if(*s == '\n')
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
++s;
|
||||
}
|
||||
out:
|
||||
lexer->pos = s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a quoted token starting after the opening '"'. Handles \n, \r, \t
|
||||
* escape sequences. Advances *tok_endp past the closing '"'.
|
||||
*
|
||||
* Returns NETRC_OK or error.
|
||||
*/
|
||||
static NETRCcode netrc_lexer_quoted(struct netrc_lexer *lexer)
|
||||
{
|
||||
NETRCcode rc = NETRC_SYNTAX_ERROR;
|
||||
const char *s = lexer->pos;
|
||||
bool escape = FALSE;
|
||||
CURLcode result;
|
||||
|
||||
DEBUGASSERT(*s == '\"');
|
||||
++s; /* pass the leading quote */
|
||||
while(*s) {
|
||||
char c = *s;
|
||||
if(escape) {
|
||||
escape = FALSE;
|
||||
switch(c) {
|
||||
case 'n':
|
||||
c = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
c = '\r';
|
||||
break;
|
||||
case 't':
|
||||
c = '\t';
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(c == '\\') {
|
||||
escape = TRUE;
|
||||
++s;
|
||||
continue;
|
||||
}
|
||||
else if(c == '\"') {
|
||||
++s; /* pass the ending quote */
|
||||
rc = NETRC_OK;
|
||||
goto out;
|
||||
}
|
||||
result = curlx_dyn_addn(&lexer->literal, &c, 1);
|
||||
if(result) {
|
||||
rc = curl2netrc(result);
|
||||
goto out;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
out:
|
||||
lexer->pos = s;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void netrc_lexer_push(struct netrc_lexer *lexer)
|
||||
{
|
||||
lexer->pushed = TRUE;
|
||||
}
|
||||
|
||||
static NETRCcode netrc_lexer_next(struct netrc_lexer *lexer,
|
||||
bool want_literal)
|
||||
{
|
||||
const char *s = lexer->pos, *start;
|
||||
NETRCcode rc = NETRC_OK;
|
||||
size_t slen;
|
||||
CURLcode result;
|
||||
|
||||
if(lexer->pushed) {
|
||||
lexer->pushed = FALSE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
curlx_dyn_reset(&lexer->literal);
|
||||
netrc_skip_blanks(lexer);
|
||||
s = lexer->pos;
|
||||
|
||||
switch(*s) {
|
||||
case 0:
|
||||
lexer->token = NETRC_TOK_EOF;
|
||||
break;
|
||||
case '\"':
|
||||
rc = netrc_lexer_quoted(lexer);
|
||||
lexer->token = NETRC_TOK_LITERAL;
|
||||
s = lexer->pos;
|
||||
break;
|
||||
default:
|
||||
/* unquoted token */
|
||||
start = s;
|
||||
while(*s && !ISBLANK(*s) && !ISNEWLINE(*s))
|
||||
++s;
|
||||
slen = s - start;
|
||||
if(!slen) {
|
||||
rc = NETRC_SYNTAX_ERROR;
|
||||
}
|
||||
if(want_literal) {
|
||||
lexer->token = NETRC_TOK_LITERAL;
|
||||
result = curlx_dyn_addn(&lexer->literal, start, slen);
|
||||
rc = curl2netrc(result);
|
||||
}
|
||||
else if((slen == 7) && curl_strnequal(start, "machine", slen)) {
|
||||
lexer->token = NETRC_TOK_MACHINE;
|
||||
}
|
||||
else if((slen == 7) && curl_strnequal(start, "default", slen)) {
|
||||
lexer->token = NETRC_TOK_DEFAULT;
|
||||
}
|
||||
else if((slen == 7) && curl_strnequal(start, "account", slen)) {
|
||||
lexer->token = NETRC_TOK_ACCOUNT;
|
||||
}
|
||||
else if((slen == 5) && curl_strnequal(start, "login", slen)) {
|
||||
lexer->token = NETRC_TOK_LOGIN;
|
||||
}
|
||||
else if((slen == 8) && curl_strnequal(start, "password", slen)) {
|
||||
lexer->token = NETRC_TOK_PASSWD;
|
||||
}
|
||||
else if((slen == 6) && curl_strnequal(start, "macdef", slen)) {
|
||||
lexer->token = NETRC_TOK_MACDEF;
|
||||
}
|
||||
else {
|
||||
lexer->token = NETRC_TOK_JUNK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
#if NETRC_DEBUG
|
||||
CURL_TRC_M(lexer->data, "[NETRC] token %s '%s', rc=%d",
|
||||
netrc_tokenstr(lexer->token),
|
||||
curlx_dyn_ptr(&lexer->literal), rc);
|
||||
#endif
|
||||
lexer->pos = s;
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct netrc_scanner {
|
||||
struct netrc_lexer lexer;
|
||||
const char *hostname; /* non-NULL, machine to scan for */
|
||||
const char *user; /* maybe NULL, login to scan for */
|
||||
char *login;
|
||||
char *passwd;
|
||||
struct Curl_creds *creds;
|
||||
bool matches_host;
|
||||
bool found;
|
||||
};
|
||||
|
||||
static void netrc_scan_reset(struct netrc_scanner *sc)
|
||||
{
|
||||
curlx_safefree(sc->login);
|
||||
curlx_safefree(sc->passwd);
|
||||
sc->matches_host = FALSE;
|
||||
}
|
||||
|
||||
static void netrc_scan_init(struct netrc_scanner *sc,
|
||||
struct Curl_easy *data,
|
||||
const char *content,
|
||||
const char *hostname,
|
||||
const char *user)
|
||||
{
|
||||
memset(sc, 0, sizeof(*sc));
|
||||
netrc_lexer_init(&sc->lexer, data, content);
|
||||
sc->hostname = hostname;
|
||||
sc->user = (user && user[0]) ? user : NULL;
|
||||
netrc_scan_reset(sc);
|
||||
}
|
||||
|
||||
static void netrc_scan_cleanup(struct netrc_scanner *sc)
|
||||
{
|
||||
netrc_scan_reset(sc);
|
||||
sc->hostname = NULL;
|
||||
sc->user = NULL;
|
||||
Curl_creds_unlink(&sc->creds);
|
||||
netrc_lexer_cleanup(&sc->lexer);
|
||||
}
|
||||
|
||||
static NETRCcode netrc_scan_literal(struct netrc_scanner *sc,
|
||||
char **pdest)
|
||||
{
|
||||
NETRCcode rc = netrc_lexer_next(&sc->lexer, TRUE);
|
||||
if(!rc) {
|
||||
if(sc->lexer.token == NETRC_TOK_LITERAL) {
|
||||
if(pdest && sc->matches_host) {
|
||||
curlx_free(*pdest);
|
||||
*pdest = curlx_strdup(curlx_dyn_ptr(&sc->lexer.literal));
|
||||
if(!*pdest)
|
||||
rc = NETRC_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
else
|
||||
netrc_lexer_push(&sc->lexer);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static NETRCcode netrc_scan_end_entry(struct netrc_scanner *sc)
|
||||
{
|
||||
NETRCcode rc = NETRC_OK;
|
||||
#if NETRC_DEBUG
|
||||
CURL_TRC_M(sc->lexer.data,
|
||||
"[NETRC] entry matches_host=%d, login='%s', passwd='%s'",
|
||||
sc->matches_host, sc->login, sc->passwd);
|
||||
#endif
|
||||
if(sc->matches_host) {
|
||||
if(sc->login) {
|
||||
if(sc->user) {
|
||||
if(Curl_timestrcmp(sc->user, sc->login))
|
||||
goto out;
|
||||
/* We look for a specific user,
|
||||
* entry is only interesting with password */
|
||||
sc->found = !!sc->passwd;
|
||||
}
|
||||
else {
|
||||
sc->found = TRUE;
|
||||
}
|
||||
}
|
||||
else if(sc->passwd) {
|
||||
/* found a passwd that applies to any user */
|
||||
sc->found = TRUE;
|
||||
}
|
||||
else {
|
||||
/* entry has nothing interesting */
|
||||
}
|
||||
if(sc->found) {
|
||||
#if NETRC_DEBUG
|
||||
CURL_TRC_M(sc->lexer.data, "[NETRC] entry match found");
|
||||
#endif
|
||||
if(Curl_creds_create(sc->user ? sc->user : sc->login, sc->passwd,
|
||||
NULL, NULL, NULL, CREDS_NETRC, &sc->creds))
|
||||
rc = NETRC_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
out:
|
||||
netrc_scan_reset(sc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static NETRCcode netrc_scan(struct Curl_easy *data,
|
||||
const char *content,
|
||||
const char *hostname,
|
||||
const char *user,
|
||||
struct Curl_creds **pcreds)
|
||||
{
|
||||
struct netrc_scanner sc;
|
||||
NETRCcode rc = NETRC_OK;
|
||||
|
||||
Curl_creds_unlink(pcreds);
|
||||
netrc_scan_init(&sc, data, content, hostname, user);
|
||||
|
||||
while(!rc && !sc.found) {
|
||||
rc = netrc_lexer_next(&sc.lexer, FALSE);
|
||||
if(!rc) {
|
||||
/* Does this token end any previous entry? */
|
||||
switch(sc.lexer.token) {
|
||||
case NETRC_TOK_EOF:
|
||||
case NETRC_TOK_MACHINE:
|
||||
case NETRC_TOK_DEFAULT:
|
||||
case NETRC_TOK_MACDEF:
|
||||
rc = netrc_scan_end_entry(&sc);
|
||||
if(rc || sc.found)
|
||||
goto out;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch(sc.lexer.token) {
|
||||
case NETRC_TOK_EOF:
|
||||
goto out;
|
||||
case NETRC_TOK_MACHINE:
|
||||
rc = netrc_lexer_next(&sc.lexer, TRUE);
|
||||
if(!rc) {
|
||||
if(sc.lexer.token == NETRC_TOK_LITERAL) {
|
||||
sc.matches_host = curl_strequal(
|
||||
sc.hostname, curlx_dyn_ptr(&sc.lexer.literal));
|
||||
}
|
||||
else {
|
||||
sc.matches_host = FALSE;
|
||||
netrc_lexer_push(&sc.lexer);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NETRC_TOK_DEFAULT:
|
||||
sc.matches_host = TRUE;
|
||||
break;
|
||||
case NETRC_TOK_ACCOUNT:
|
||||
rc = netrc_scan_literal(&sc, NULL); /* ignore, not used */
|
||||
break;
|
||||
case NETRC_TOK_LOGIN:
|
||||
rc = netrc_scan_literal(&sc, &sc.login);
|
||||
break;
|
||||
case NETRC_TOK_PASSWD:
|
||||
rc = netrc_scan_literal(&sc, &sc.passwd);
|
||||
break;
|
||||
case NETRC_TOK_MACDEF:
|
||||
netrc_skip_to_empty_line(&sc.lexer);
|
||||
break;
|
||||
case NETRC_TOK_LITERAL:
|
||||
case NETRC_TOK_JUNK:
|
||||
default:
|
||||
/* skip this */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if(!rc) {
|
||||
if(sc.creds)
|
||||
Curl_creds_link(pcreds, sc.creds);
|
||||
else
|
||||
rc = NETRC_NO_MATCH;
|
||||
}
|
||||
netrc_scan_cleanup(&sc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static NETRCcode file2memory(const char *filename, struct dynbuf *filebuf)
|
||||
{
|
||||
|
|
@ -107,393 +538,25 @@ static NETRCcode file2memory(const char *filename, struct dynbuf *filebuf)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* bundled parser state to keep function signatures compact */
|
||||
struct netrc_state {
|
||||
struct Curl_creds *existing;
|
||||
char *login;
|
||||
char *password;
|
||||
enum host_lookup_state state;
|
||||
enum found_state keyword;
|
||||
NETRCcode retcode;
|
||||
unsigned char found; /* FOUND_LOGIN | FOUND_PASSWORD bits */
|
||||
bool our_login;
|
||||
bool done;
|
||||
};
|
||||
|
||||
/*
|
||||
* Parse a quoted token starting after the opening '"'. Handles \n, \r, \t
|
||||
* escape sequences. Advances *tok_endp past the closing '"'.
|
||||
*
|
||||
* Returns NETRC_OK or error.
|
||||
*/
|
||||
static NETRCcode netrc_quoted_token(const char **tok_endp,
|
||||
struct dynbuf *token)
|
||||
static NETRCcode netrc_scan_file(struct Curl_easy *data,
|
||||
struct store_netrc *store,
|
||||
const char *hostname,
|
||||
const char *user,
|
||||
const char *netrcfile,
|
||||
struct Curl_creds **pcreds)
|
||||
{
|
||||
bool escape = FALSE;
|
||||
NETRCcode rc = NETRC_SYNTAX_ERROR;
|
||||
const char *tok_end = *tok_endp;
|
||||
tok_end++; /* pass the leading quote */
|
||||
while(*tok_end) {
|
||||
CURLcode result;
|
||||
char s = *tok_end;
|
||||
if(escape) {
|
||||
escape = FALSE;
|
||||
switch(s) {
|
||||
case 'n':
|
||||
s = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
s = '\r';
|
||||
break;
|
||||
case 't':
|
||||
s = '\t';
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(s == '\\') {
|
||||
escape = TRUE;
|
||||
tok_end++;
|
||||
continue;
|
||||
}
|
||||
else if(s == '\"') {
|
||||
tok_end++; /* pass the ending quote */
|
||||
rc = NETRC_OK;
|
||||
break;
|
||||
}
|
||||
result = curlx_dyn_addn(token, &s, 1);
|
||||
if(result) {
|
||||
*tok_endp = tok_end;
|
||||
return curl2netrc(result);
|
||||
}
|
||||
tok_end++;
|
||||
}
|
||||
*tok_endp = tok_end;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets the next token from the netrc buffer at *tokp. Writes the token into
|
||||
* the 'token' dynbuf. Advances *tok_endp past the consumed token in the input
|
||||
* buffer. Updates *statep for MACDEF newline handling. Sets *lineend = TRUE
|
||||
* when the line is exhausted.
|
||||
*
|
||||
* Returns NETRC_OK or an error code.
|
||||
*/
|
||||
static NETRCcode netrc_get_token(const char **tokp,
|
||||
const char **tok_endp,
|
||||
struct dynbuf *token,
|
||||
enum host_lookup_state *statep,
|
||||
bool *lineend)
|
||||
{
|
||||
const char *tok = *tokp;
|
||||
const char *tok_end;
|
||||
|
||||
*lineend = FALSE;
|
||||
curlx_dyn_reset(token);
|
||||
curlx_str_passblanks(&tok);
|
||||
|
||||
/* tok is first non-space letter */
|
||||
if(*statep == MACDEF) {
|
||||
if((*tok == '\n') || (*tok == '\r'))
|
||||
*statep = NOTHING; /* end of macro definition */
|
||||
*lineend = TRUE;
|
||||
*tokp = tok;
|
||||
return NETRC_OK;
|
||||
}
|
||||
|
||||
if(!*tok || (*tok == '\n')) {
|
||||
/* end of line */
|
||||
*lineend = TRUE;
|
||||
*tokp = tok;
|
||||
return NETRC_OK;
|
||||
}
|
||||
|
||||
tok_end = tok;
|
||||
if(*tok == '\"') {
|
||||
/* quoted string */
|
||||
NETRCcode ret = netrc_quoted_token(&tok_end, token);
|
||||
if(ret)
|
||||
return ret;
|
||||
}
|
||||
else {
|
||||
/* unquoted token */
|
||||
size_t len = 0;
|
||||
CURLcode result;
|
||||
while(*tok_end > ' ') {
|
||||
tok_end++;
|
||||
len++;
|
||||
}
|
||||
if(!len)
|
||||
return NETRC_SYNTAX_ERROR;
|
||||
result = curlx_dyn_addn(token, tok, len);
|
||||
if(result)
|
||||
return curl2netrc(result);
|
||||
}
|
||||
|
||||
*tok_endp = tok_end;
|
||||
|
||||
if(curlx_dyn_len(token))
|
||||
*tokp = curlx_dyn_ptr(token);
|
||||
else
|
||||
/* set it to blank to avoid NULL */
|
||||
*tokp = "";
|
||||
|
||||
return NETRC_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset parser for a new machine entry. Frees password and optionally login
|
||||
* if it was not user-specified.
|
||||
*/
|
||||
static void netrc_new_machine(struct netrc_state *ns)
|
||||
{
|
||||
ns->keyword = NONE;
|
||||
ns->found = 0;
|
||||
ns->our_login = FALSE;
|
||||
curlx_safefree(ns->password);
|
||||
curlx_safefree(ns->login);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a parsed token through the HOSTVALID state machine branch. This
|
||||
* handles login/password values and keyword transitions for the matched host.
|
||||
*
|
||||
* Returns NETRC_OK or an error code.
|
||||
*/
|
||||
static NETRCcode netrc_hostvalid(struct netrc_state *ns, const char *tok)
|
||||
{
|
||||
if(ns->keyword == LOGIN) {
|
||||
if(Curl_creds_has_user(ns->existing))
|
||||
ns->our_login = !Curl_timestrcmp(ns->existing->user, tok);
|
||||
else {
|
||||
ns->our_login = TRUE;
|
||||
curlx_free(ns->login);
|
||||
ns->login = curlx_strdup(tok);
|
||||
if(!ns->login)
|
||||
return NETRC_OUT_OF_MEMORY;
|
||||
}
|
||||
ns->found |= FOUND_LOGIN;
|
||||
ns->keyword = NONE;
|
||||
}
|
||||
else if(ns->keyword == PASSWORD) {
|
||||
curlx_free(ns->password);
|
||||
ns->password = curlx_strdup(tok);
|
||||
if(!ns->password)
|
||||
return NETRC_OUT_OF_MEMORY;
|
||||
ns->found |= FOUND_PASSWORD;
|
||||
ns->keyword = NONE;
|
||||
}
|
||||
else if(curl_strequal("login", tok))
|
||||
ns->keyword = LOGIN;
|
||||
else if(curl_strequal("password", tok))
|
||||
ns->keyword = PASSWORD;
|
||||
else if(curl_strequal("machine", tok)) {
|
||||
/* a new machine here */
|
||||
bool specific_login = Curl_creds_has_user(ns->existing);
|
||||
|
||||
if((ns->found & FOUND_PASSWORD) &&
|
||||
/* a password was provided for this host */
|
||||
(!specific_login || ns->our_login ||
|
||||
/* and found a login that is suitable
|
||||
(either matched specific one or simply present) */
|
||||
(specific_login && !(ns->found & FOUND_LOGIN)))) {
|
||||
/* or we look for a specific login, but no login was not specified */
|
||||
|
||||
ns->done = TRUE;
|
||||
return NETRC_OK;
|
||||
}
|
||||
|
||||
ns->state = HOSTFOUND;
|
||||
netrc_new_machine(ns);
|
||||
}
|
||||
else if(curl_strequal("default", tok)) {
|
||||
ns->state = HOSTVALID;
|
||||
ns->retcode = NETRC_OK;
|
||||
netrc_new_machine(ns);
|
||||
}
|
||||
if((ns->found == (FOUND_PASSWORD | FOUND_LOGIN)) && ns->our_login)
|
||||
ns->done = TRUE;
|
||||
return NETRC_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process one parsed token through the netrc state
|
||||
* machine. Updates the parser state in *ns.
|
||||
* Returns NETRC_OK or an error code.
|
||||
*/
|
||||
static NETRCcode netrc_handle_token(struct netrc_state *ns,
|
||||
const char *tok,
|
||||
const char *host)
|
||||
{
|
||||
switch(ns->state) {
|
||||
case NOTHING:
|
||||
if(curl_strequal("macdef", tok))
|
||||
ns->state = MACDEF;
|
||||
else if(curl_strequal("machine", tok)) {
|
||||
ns->state = HOSTFOUND;
|
||||
netrc_new_machine(ns);
|
||||
}
|
||||
else if(curl_strequal("default", tok)) {
|
||||
ns->state = HOSTVALID;
|
||||
ns->retcode = NETRC_OK;
|
||||
}
|
||||
break;
|
||||
case MACDEF:
|
||||
if(!*tok)
|
||||
ns->state = NOTHING;
|
||||
break;
|
||||
case HOSTFOUND:
|
||||
if(curl_strequal(host, tok)) {
|
||||
ns->state = HOSTVALID;
|
||||
ns->retcode = NETRC_OK;
|
||||
}
|
||||
else
|
||||
ns->state = NOTHING;
|
||||
break;
|
||||
case HOSTVALID:
|
||||
return netrc_hostvalid(ns, tok);
|
||||
}
|
||||
return NETRC_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finalize the parse result: fill in defaults and free
|
||||
* resources on error.
|
||||
*/
|
||||
static NETRCcode netrc_finalize(struct netrc_state *ns,
|
||||
struct store_netrc *store,
|
||||
struct Curl_creds **pcreds)
|
||||
{
|
||||
NETRCcode retcode = ns->retcode;
|
||||
if(!retcode) {
|
||||
if(!ns->password && ns->our_login) {
|
||||
/* success without a password, set a blank one */
|
||||
ns->password = curlx_strdup("");
|
||||
if(!ns->password) {
|
||||
retcode = NETRC_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else if(!ns->login && !ns->password) {
|
||||
/* a default with no credentials */
|
||||
retcode = NETRC_NO_MATCH;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if(!retcode) {
|
||||
/* success
|
||||
netrc_finalize() can return a password even when specific_login is set
|
||||
but our_login is false (e.g., host matched but the requested login
|
||||
never matched). See test 685. */
|
||||
const char *login = Curl_creds_has_user(ns->existing) ?
|
||||
ns->existing->user : ns->login;
|
||||
/* success without a password, set a blank one */
|
||||
const char *passwd = ns->password ? ns->password : "";
|
||||
|
||||
if(Curl_creds_create(login, passwd, NULL, NULL, NULL, CREDS_NETRC,
|
||||
pcreds)) {
|
||||
retcode = NETRC_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
curlx_free(ns->login);
|
||||
curlx_free(ns->password);
|
||||
if(retcode) {
|
||||
curlx_dyn_free(&store->filebuf);
|
||||
store->loaded = FALSE;
|
||||
}
|
||||
return retcode;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns zero on success.
|
||||
*/
|
||||
static NETRCcode parsenetrc(struct store_netrc *store,
|
||||
const char *host,
|
||||
struct Curl_creds *existing,
|
||||
const char *netrcfile,
|
||||
struct Curl_creds **pcreds)
|
||||
{
|
||||
const char *netrcbuffer;
|
||||
struct dynbuf token;
|
||||
struct dynbuf *filebuf = &store->filebuf;
|
||||
struct netrc_state ns;
|
||||
|
||||
DEBUGASSERT(!existing || !Curl_creds_has_passwd(existing));
|
||||
memset(&ns, 0, sizeof(ns));
|
||||
ns.retcode = NETRC_NO_MATCH;
|
||||
ns.existing = existing;
|
||||
|
||||
curlx_dyn_init(&token, MAX_NETRC_TOKEN);
|
||||
|
||||
if(!store->loaded) {
|
||||
NETRCcode ret = file2memory(netrcfile, filebuf);
|
||||
if(ret)
|
||||
if(ret) {
|
||||
CURL_TRC_M(data, "[NETRC] could not load '%s'", netrcfile);
|
||||
return ret;
|
||||
}
|
||||
store->loaded = TRUE;
|
||||
}
|
||||
|
||||
netrcbuffer = curlx_dyn_ptr(filebuf);
|
||||
|
||||
while(!ns.done) {
|
||||
const char *tok = netrcbuffer;
|
||||
while(tok && !ns.done) {
|
||||
const char *tok_end;
|
||||
bool lineend;
|
||||
NETRCcode ret;
|
||||
|
||||
ret = netrc_get_token(&tok, &tok_end, &token, &ns.state, &lineend);
|
||||
if(ret) {
|
||||
ns.retcode = ret;
|
||||
goto out;
|
||||
}
|
||||
if(lineend)
|
||||
break;
|
||||
|
||||
ret = netrc_handle_token(&ns, tok, host);
|
||||
if(ret) {
|
||||
ns.retcode = ret;
|
||||
goto out;
|
||||
}
|
||||
/* tok_end cannot point to a null byte here since lines are always
|
||||
newline terminated */
|
||||
DEBUGASSERT(*tok_end);
|
||||
tok = ++tok_end;
|
||||
}
|
||||
if(!ns.done) {
|
||||
const char *nl = NULL;
|
||||
if(tok)
|
||||
nl = strchr(tok, '\n');
|
||||
if(!nl)
|
||||
break;
|
||||
/* point to next line */
|
||||
netrcbuffer = &nl[1];
|
||||
}
|
||||
} /* while !done */
|
||||
|
||||
out:
|
||||
curlx_dyn_free(&token);
|
||||
return netrc_finalize(&ns, store, pcreds);
|
||||
}
|
||||
|
||||
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 */
|
||||
return netrc_scan(data, curlx_dyn_ptr(filebuf), hostname, user, pcreds);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -502,14 +565,18 @@ const char *Curl_netrc_strerror(NETRCcode ret)
|
|||
* *loginp and *passwordp MUST be allocated if they are not NULL when passed
|
||||
* in.
|
||||
*/
|
||||
NETRCcode Curl_parsenetrc(struct store_netrc *store, const char *host,
|
||||
struct Curl_creds *existing,
|
||||
NETRCcode Curl_netrc_scan(struct Curl_easy *data,
|
||||
struct store_netrc *store,
|
||||
const char *hostname,
|
||||
const char *user,
|
||||
const char *netrcfile,
|
||||
struct Curl_creds **pcreds)
|
||||
{
|
||||
NETRCcode retcode = NETRC_OK;
|
||||
char *filealloc = NULL;
|
||||
|
||||
CURL_TRC_M(data, "[NETRC] scanning '%s' for host '%s' user '%s'",
|
||||
netrcfile, hostname, user);
|
||||
Curl_creds_unlink(pcreds);
|
||||
if(!netrcfile) {
|
||||
char *home = NULL;
|
||||
|
|
@ -559,7 +626,8 @@ NETRCcode Curl_parsenetrc(struct store_netrc *store, const char *host,
|
|||
goto out;
|
||||
}
|
||||
}
|
||||
retcode = parsenetrc(store, host, existing, filealloc, pcreds);
|
||||
retcode = netrc_scan_file(
|
||||
data, store, hostname, user, filealloc, pcreds);
|
||||
curlx_free(filealloc);
|
||||
#ifdef _WIN32
|
||||
if(retcode == NETRC_FILE_MISSING) {
|
||||
|
|
@ -569,14 +637,17 @@ NETRCcode Curl_parsenetrc(struct store_netrc *store, const char *host,
|
|||
curlx_free(homea);
|
||||
return NETRC_OUT_OF_MEMORY;
|
||||
}
|
||||
retcode = parsenetrc(store, host, existing, filealloc, pcreds);
|
||||
retcode = netrc_scan_file(
|
||||
data, store, hostname, user, filealloc, pcreds);
|
||||
curlx_free(filealloc);
|
||||
}
|
||||
#endif
|
||||
curlx_free(homea);
|
||||
}
|
||||
else
|
||||
retcode = parsenetrc(store, host, existing, netrcfile, pcreds);
|
||||
retcode = netrc_scan_file(
|
||||
data, store, hostname, user, netrcfile, pcreds);
|
||||
|
||||
out:
|
||||
if(retcode)
|
||||
Curl_creds_unlink(pcreds);
|
||||
|
|
@ -593,4 +664,22 @@ void Curl_netrc_cleanup(struct store_netrc *store)
|
|||
curlx_dyn_free(&store->filebuf);
|
||||
store->loaded = FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
#endif /* !CURL_DISABLE_NETRC */
|
||||
|
|
|
|||
14
lib/netrc.h
14
lib/netrc.h
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "curlx/dynbuf.h"
|
||||
|
||||
struct Curl_easy;
|
||||
struct Curl_creds;
|
||||
|
||||
struct store_netrc {
|
||||
|
|
@ -50,15 +51,14 @@ const char *Curl_netrc_strerror(NETRCcode ret);
|
|||
void Curl_netrc_init(struct store_netrc *store);
|
||||
void Curl_netrc_cleanup(struct store_netrc *store);
|
||||
|
||||
NETRCcode Curl_parsenetrc(struct store_netrc *store, const char *host,
|
||||
struct Curl_creds *existing,
|
||||
/* Scan a netrc file for credentials matching hostname
|
||||
* and optional user. */
|
||||
NETRCcode Curl_netrc_scan(struct Curl_easy *data,
|
||||
struct store_netrc *store,
|
||||
const char *hostname,
|
||||
const char *user,
|
||||
const char *netrcfile,
|
||||
struct Curl_creds **pcreds);
|
||||
/* Assume: (*passwordp)[0]=0, host[0] != 0.
|
||||
* If (*loginp)[0] = 0, search for login and password within a machine
|
||||
* section in the netrc.
|
||||
* If (*loginp)[0] != 0, search for password within machine and login.
|
||||
*/
|
||||
#else
|
||||
/* disabled */
|
||||
#define Curl_netrc_init(x)
|
||||
|
|
|
|||
153
lib/url.c
153
lib/url.c
|
|
@ -2161,14 +2161,11 @@ static bool str_has_ctrl(const char *input)
|
|||
static CURLcode override_login(struct Curl_easy *data,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
CURLUcode uc;
|
||||
char **optionsp = &conn->options;
|
||||
#ifndef CURL_DISABLE_NETRC
|
||||
struct Curl_creds *ncreds_in = NULL;
|
||||
struct Curl_creds *ncreds_out = NULL;
|
||||
#endif
|
||||
CURLcode result = CURLE_OK;
|
||||
bool creds_changed = FALSE;
|
||||
|
||||
if(data->set.str[STRING_OPTIONS]) {
|
||||
curlx_free(*optionsp);
|
||||
|
|
@ -2180,107 +2177,97 @@ static CURLcode override_login(struct Curl_easy *data,
|
|||
}
|
||||
|
||||
#ifndef CURL_DISABLE_NETRC
|
||||
if(data->set.use_netrc) {
|
||||
/* Determine how to react on already existing credentials */
|
||||
if(data->set.use_netrc == CURL_NETRC_REQUIRED) {
|
||||
Curl_creds_unlink(&conn->creds);
|
||||
}
|
||||
if(data->set.use_netrc) { /* not CURL_NETRC_IGNORED */
|
||||
struct Curl_creds *ncreds_in = NULL;
|
||||
bool scan_netrc = TRUE;
|
||||
NETRCcode ret;
|
||||
CURLUcode uc;
|
||||
|
||||
if(data->state.creds) {
|
||||
switch(data->state.creds->source) {
|
||||
case CREDS_OPTION:
|
||||
/* we never override credentials set via CURLOPT_* */
|
||||
goto out;
|
||||
case CREDS_URL:
|
||||
/* we never override credentials set via CURLOPT_*, leave. */
|
||||
scan_netrc = FALSE;
|
||||
break;
|
||||
case CREDS_URL: /* only apply when netrc is not required */
|
||||
if(data->set.use_netrc == CURL_NETRC_REQUIRED) {
|
||||
/* use the URL user to search netrc */
|
||||
result = Curl_creds_create(
|
||||
data->state.creds->user, NULL, NULL, NULL, NULL, CREDS_URL,
|
||||
&ncreds_in);
|
||||
if(result)
|
||||
goto out;
|
||||
/* We ignore password from URL */
|
||||
ncreds_in = data->state.creds;
|
||||
}
|
||||
else if(!Curl_creds_has_user(data->state.creds) ||
|
||||
!Curl_creds_has_passwd(data->state.creds)) {
|
||||
/* We use netrc to complete what is missing */
|
||||
ncreds_in = data->state.creds;
|
||||
}
|
||||
else
|
||||
/* only search when something is still missing */
|
||||
Curl_creds_link(&ncreds_in, data->state.creds);
|
||||
scan_netrc = FALSE;
|
||||
break;
|
||||
default:
|
||||
/* ignore credentials from other sources */
|
||||
default: /* ignore credentials from other sources */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Only search in netrc when the creds are not already complete */
|
||||
if(!Curl_creds_has_passwd(ncreds_in)) {
|
||||
NETRCcode ret;
|
||||
if(!scan_netrc)
|
||||
goto out;
|
||||
|
||||
CURL_TRC_M(data, "netrc: find credentials for %s, user %s",
|
||||
conn->origin->hostname,
|
||||
Curl_creds_has_user(ncreds_in) ? ncreds_in->user : "*");
|
||||
ret = Curl_parsenetrc(&data->state.netrc,
|
||||
conn->origin->hostname,
|
||||
ncreds_in,
|
||||
data->set.str[STRING_NETRC_FILE],
|
||||
&ncreds_out);
|
||||
DEBUGASSERT(!ret || !ncreds_out);
|
||||
if(ret == NETRC_OUT_OF_MEMORY) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
else if(ret && ((ret == NETRC_NO_MATCH) ||
|
||||
(data->set.use_netrc == CURL_NETRC_OPTIONAL))) {
|
||||
infof(data, "Could not find host %s in the %s file; using defaults",
|
||||
conn->origin->hostname,
|
||||
(data->set.str[STRING_NETRC_FILE] ?
|
||||
data->set.str[STRING_NETRC_FILE] : ".netrc"));
|
||||
}
|
||||
else if(ret) {
|
||||
const char *m = Curl_netrc_strerror(ret);
|
||||
failf(data, ".netrc error: %s", m);
|
||||
result = CURLE_READ_ERROR;
|
||||
goto out;
|
||||
}
|
||||
else if(ncreds_out) {
|
||||
if(!(conn->scheme->flags & PROTOPT_USERPWDCTRL)) {
|
||||
/* if the protocol cannot handle control codes in credentials, make
|
||||
sure there are none */
|
||||
if(str_has_ctrl(ncreds_out->user) ||
|
||||
str_has_ctrl(ncreds_out->passwd)) {
|
||||
failf(data, "control code detected in .netrc credentials");
|
||||
result = CURLE_READ_ERROR;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
CURL_TRC_M(data, "netrc: using credentials for %s as %s",
|
||||
conn->origin->hostname, ncreds_out->user);
|
||||
result = Curl_creds_merge(ncreds_out->user, ncreds_out->passwd,
|
||||
data->state.creds, CREDS_NETRC,
|
||||
&data->state.creds);
|
||||
if(result)
|
||||
ret = Curl_netrc_scan(data, &data->state.netrc,
|
||||
conn->origin->hostname,
|
||||
Curl_creds_user(ncreds_in),
|
||||
data->set.str[STRING_NETRC_FILE],
|
||||
&ncreds_out);
|
||||
DEBUGASSERT(!ret || !ncreds_out);
|
||||
if(ret == NETRC_OUT_OF_MEMORY) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
else if(ret && ((ret == NETRC_NO_MATCH) ||
|
||||
(data->set.use_netrc == CURL_NETRC_OPTIONAL))) {
|
||||
infof(data, "Could not find host %s in the %s file; using defaults",
|
||||
conn->origin->hostname,
|
||||
(data->set.str[STRING_NETRC_FILE] ?
|
||||
data->set.str[STRING_NETRC_FILE] : ".netrc"));
|
||||
}
|
||||
else if(ret) {
|
||||
const char *m = Curl_netrc_strerror(ret);
|
||||
failf(data, ".netrc error: %s", m);
|
||||
result = CURLE_READ_ERROR;
|
||||
goto out;
|
||||
}
|
||||
else if(ncreds_out) {
|
||||
if(!(conn->scheme->flags & PROTOPT_USERPWDCTRL)) {
|
||||
/* if the protocol cannot handle control codes in credentials, make
|
||||
sure there are none */
|
||||
if(str_has_ctrl(ncreds_out->user) ||
|
||||
str_has_ctrl(ncreds_out->passwd)) {
|
||||
failf(data, "control code detected in .netrc credentials");
|
||||
result = CURLE_READ_ERROR;
|
||||
goto out;
|
||||
creds_changed = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
DEBUGASSERT(0);
|
||||
CURL_TRC_M(data, "netrc: using credentials for %s as %s",
|
||||
conn->origin->hostname, ncreds_out->user);
|
||||
result = Curl_creds_merge(ncreds_out->user, ncreds_out->passwd,
|
||||
data->state.creds, CREDS_NETRC,
|
||||
&data->state.creds);
|
||||
if(result)
|
||||
goto out;
|
||||
/* for updated strings, we update them in the URL */
|
||||
uc = curl_url_set(data->state.uh, CURLUPART_USER,
|
||||
Curl_creds_user(data->state.creds), CURLU_URLENCODE);
|
||||
if(!uc)
|
||||
uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
|
||||
Curl_creds_passwd(data->state.creds),
|
||||
CURLU_URLENCODE);
|
||||
if(uc)
|
||||
result = Curl_uc_to_curlcode(uc);
|
||||
}
|
||||
else
|
||||
DEBUGASSERT(0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if(creds_changed) {
|
||||
/* for updated strings, we update them in the URL */
|
||||
uc = curl_url_set(data->state.uh, CURLUPART_USER,
|
||||
Curl_creds_user(data->state.creds), CURLU_URLENCODE);
|
||||
if(!uc)
|
||||
uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
|
||||
Curl_creds_passwd(data->state.creds), CURLU_URLENCODE);
|
||||
if(uc)
|
||||
result = Curl_uc_to_curlcode(uc);
|
||||
}
|
||||
|
||||
out:
|
||||
#ifndef CURL_DISABLE_NETRC
|
||||
Curl_creds_unlink(&ncreds_in);
|
||||
Curl_creds_unlink(&ncreds_out);
|
||||
#endif
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -27,21 +27,23 @@
|
|||
#include "netrc.h"
|
||||
#include "creds.h"
|
||||
|
||||
static void t1304_stop(struct Curl_creds **pc1, struct Curl_creds **pc2)
|
||||
static CURLcode t1304_setup(struct Curl_easy **easy)
|
||||
{
|
||||
Curl_creds_unlink(pc1);
|
||||
Curl_creds_unlink(pc2);
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
global_init(CURL_GLOBAL_ALL);
|
||||
*easy = curl_easy_init();
|
||||
if(!*easy) {
|
||||
curl_global_cleanup();
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool t1304_set_creds(const char *user, const char *passwd,
|
||||
struct Curl_creds **pcreds)
|
||||
static void t1304_stop(struct Curl_easy *easy)
|
||||
{
|
||||
Curl_creds_unlink(pcreds);
|
||||
if(user || passwd)
|
||||
return !Curl_creds_create(user, passwd, NULL, NULL, NULL, CREDS_NONE,
|
||||
pcreds);
|
||||
else
|
||||
return TRUE;
|
||||
curl_easy_cleanup(easy);
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
static bool t1304_no_user(struct Curl_creds *creds)
|
||||
|
|
@ -56,130 +58,105 @@ static bool t1304_no_passwd(struct Curl_creds *creds)
|
|||
|
||||
static CURLcode test_unit1304(const char *arg)
|
||||
{
|
||||
struct Curl_creds *cr_out = NULL, *cr_in = NULL;
|
||||
|
||||
UNITTEST_BEGIN_SIMPLE
|
||||
|
||||
struct Curl_creds *cr_out = NULL;
|
||||
struct Curl_easy *data;
|
||||
int result;
|
||||
struct store_netrc store;
|
||||
|
||||
UNITTEST_BEGIN(t1304_setup(&data))
|
||||
|
||||
/*
|
||||
* Test a non existent host in our netrc file.
|
||||
*/
|
||||
Curl_netrc_init(&store);
|
||||
result = Curl_parsenetrc(&store, "test.example.com", NULL, arg, &cr_out);
|
||||
result = Curl_netrc_scan(
|
||||
data, &store, "test.example.com", NULL, arg, &cr_out);
|
||||
fail_unless(result == 1, "expected no match");
|
||||
abort_unless(cr_out == NULL, "creds did not return NULL!");
|
||||
fail_unless(cr_out == NULL, "creds did not return NULL!");
|
||||
Curl_netrc_cleanup(&store);
|
||||
|
||||
/*
|
||||
* Test a non existent login in our netrc file.
|
||||
*/
|
||||
fail_unless(t1304_set_creds("me", NULL, &cr_in), "err set creds");
|
||||
Curl_netrc_init(&store);
|
||||
result = Curl_parsenetrc(&store, "example.com", cr_in, arg, &cr_out);
|
||||
result = Curl_netrc_scan(data, &store, "example.com", "me", arg, &cr_out);
|
||||
fail_unless(result == 1, "expected no match");
|
||||
abort_unless(t1304_no_passwd(cr_out), "password is not NULL!");
|
||||
fail_unless(t1304_no_passwd(cr_out), "password is not NULL!");
|
||||
Curl_netrc_cleanup(&store);
|
||||
|
||||
/*
|
||||
* Test a non existent login and host in our netrc file.
|
||||
*/
|
||||
fail_unless(t1304_set_creds("me", NULL, &cr_in), "err set creds");
|
||||
Curl_netrc_init(&store);
|
||||
result = Curl_parsenetrc(&store, "test.example.com", cr_in, arg, &cr_out);
|
||||
result = Curl_netrc_scan(
|
||||
data, &store, "test.example.com", "me", arg, &cr_out);
|
||||
fail_unless(result == 1, "expected no match");
|
||||
abort_unless(t1304_no_passwd(cr_out), "password is not NULL!");
|
||||
fail_unless(t1304_no_passwd(cr_out), "password is not NULL!");
|
||||
Curl_netrc_cleanup(&store);
|
||||
|
||||
/*
|
||||
* Test a non existent login (substring of an existing one) in our
|
||||
* netrc file.
|
||||
*/
|
||||
fail_unless(t1304_set_creds(
|
||||
"admi", NULL, &cr_in), "err set creds"); /* spellchecker:disable-line */
|
||||
Curl_netrc_init(&store);
|
||||
result = Curl_parsenetrc(&store, "example.com", cr_in, arg, &cr_out);
|
||||
result = Curl_netrc_scan(
|
||||
data, &store, "example.com", "a", arg, &cr_out);
|
||||
fail_unless(result == 1, "expected no match");
|
||||
abort_unless(t1304_no_passwd(cr_out), "password is not NULL!");
|
||||
fail_unless(t1304_no_passwd(cr_out), "password is not NULL!");
|
||||
Curl_netrc_cleanup(&store);
|
||||
|
||||
/*
|
||||
* Test a non existent login (superstring of an existing one)
|
||||
* in our netrc file.
|
||||
*/
|
||||
fail_unless(t1304_set_creds("adminn", NULL, &cr_in), "err set creds");
|
||||
Curl_netrc_init(&store);
|
||||
result = Curl_parsenetrc(&store, "example.com", cr_in, arg, &cr_out);
|
||||
result = Curl_netrc_scan(
|
||||
data, &store, "example.com", "administrator", arg, &cr_out);
|
||||
fail_unless(result == 1, "expected no match");
|
||||
abort_unless(t1304_no_passwd(cr_out), "password is not NULL!");
|
||||
fail_unless(t1304_no_passwd(cr_out), "password is not NULL!");
|
||||
Curl_netrc_cleanup(&store);
|
||||
|
||||
/*
|
||||
* Test for the first existing host in our netrc file
|
||||
* with login[0] = 0.
|
||||
* Test for the first existing host in our netrc file with no user
|
||||
*/
|
||||
Curl_creds_unlink(&cr_in);
|
||||
Curl_netrc_init(&store);
|
||||
result = Curl_parsenetrc(&store, "example.com", cr_in, arg, &cr_out);
|
||||
result = Curl_netrc_scan(data, &store, "example.com", NULL, arg, &cr_out);
|
||||
fail_unless(result == 0, "Host should have been found");
|
||||
abort_unless(!t1304_no_passwd(cr_out), "returned NULL!");
|
||||
fail_unless(strncmp(Curl_creds_passwd(cr_out), "passwd", 6) == 0,
|
||||
"password should be 'passwd'");
|
||||
abort_unless(!t1304_no_user(cr_out), "returned NULL!");
|
||||
fail_unless(!t1304_no_user(cr_out), "returned NULL!");
|
||||
fail_unless(strncmp(Curl_creds_user(cr_out), "admin", 5) == 0,
|
||||
"login should be 'admin'");
|
||||
Curl_netrc_cleanup(&store);
|
||||
|
||||
/*
|
||||
* Test for the first existing host in our netrc file
|
||||
* with login[0] != 0.
|
||||
* Test for the second existing host in our netrc file with no user
|
||||
*/
|
||||
Curl_creds_unlink(&cr_in);
|
||||
Curl_netrc_init(&store);
|
||||
result = Curl_parsenetrc(&store, "example.com", cr_in, arg, &cr_out);
|
||||
result = Curl_netrc_scan(
|
||||
data, &store, "curl.example.com", NULL, arg, &cr_out);
|
||||
fail_unless(result == 0, "Host should have been found");
|
||||
abort_unless(!t1304_no_passwd(cr_out), "returned NULL!");
|
||||
fail_unless(strncmp(Curl_creds_passwd(cr_out), "passwd", 6) == 0,
|
||||
"password should be 'passwd'");
|
||||
abort_unless(!t1304_no_user(cr_out), "returned NULL!");
|
||||
fail_unless(strncmp(Curl_creds_user(cr_out), "admin", 5) == 0,
|
||||
"login should be 'admin'");
|
||||
Curl_netrc_cleanup(&store);
|
||||
|
||||
/*
|
||||
* Test for the second existing host in our netrc file
|
||||
* with login[0] = 0.
|
||||
*/
|
||||
Curl_creds_unlink(&cr_in);
|
||||
Curl_netrc_init(&store);
|
||||
result = Curl_parsenetrc(&store, "curl.example.com", cr_in, arg, &cr_out);
|
||||
fail_unless(result == 0, "Host should have been found");
|
||||
abort_unless(!t1304_no_passwd(cr_out), "returned NULL!");
|
||||
fail_unless(strncmp(Curl_creds_passwd(cr_out), "none", 4) == 0,
|
||||
"password should be 'none'");
|
||||
abort_unless(!t1304_no_user(cr_out), "returned NULL!");
|
||||
fail_unless(!t1304_no_user(cr_out), "returned NULL!");
|
||||
fail_unless(strncmp(Curl_creds_user(cr_out), "none", 4) == 0,
|
||||
"login should be 'none'");
|
||||
Curl_netrc_cleanup(&store);
|
||||
|
||||
/*
|
||||
* Test for the second existing host in our netrc file
|
||||
* with login[0] != 0.
|
||||
* Test for the last host where we do not want to see the password
|
||||
* if the login does not match.
|
||||
*/
|
||||
Curl_creds_unlink(&cr_in);
|
||||
Curl_netrc_init(&store);
|
||||
result = Curl_parsenetrc(&store, "curl.example.com", cr_in, arg, &cr_out);
|
||||
fail_unless(result == 0, "Host should have been found");
|
||||
abort_unless(!t1304_no_passwd(cr_out), "returned NULL!");
|
||||
fail_unless(strncmp(Curl_creds_passwd(cr_out), "none", 4) == 0,
|
||||
"password should be 'none'");
|
||||
abort_unless(!t1304_no_user(cr_out), "returned NULL!");
|
||||
fail_unless(strncmp(Curl_creds_user(cr_out), "none", 4) == 0,
|
||||
"login should be 'none'");
|
||||
result = Curl_netrc_scan(
|
||||
data, &store, "curl.example.com", "hilarious", arg, &cr_out);
|
||||
fail_unless(result == 1, "expect no match");
|
||||
fail_unless(!Curl_creds_has_passwd(cr_out), "password must be NULL");
|
||||
Curl_netrc_cleanup(&store);
|
||||
|
||||
UNITTEST_END(t1304_stop(&cr_in, &cr_out))
|
||||
Curl_creds_unlink(&cr_out);
|
||||
|
||||
UNITTEST_END(t1304_stop(data))
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue