security.c: factored the logic from Curl_sec_login into a dedicated method that better reflect its intent.
Introduced a helper method ftp_send_command that synchronously send an FTP query.
This commit is contained in:
committed by
Daniel Stenberg
parent
512a82d395
commit
1d95a48fe9
109
lib/security.c
109
lib/security.c
@@ -101,6 +101,27 @@ static const struct Curl_sec_client_mech * const mechs[] = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Send an FTP command defined by |message| and the optional arguments. The
|
||||||
|
function returns the ftp_code. If an error occurs, -1 is returned. */
|
||||||
|
static int ftp_send_command(struct connectdata *conn, const char *message, ...)
|
||||||
|
{
|
||||||
|
int ftp_code;
|
||||||
|
ssize_t nread;
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start(args, message);
|
||||||
|
if(Curl_ftpsendf(conn, message, args) != CURLE_OK) {
|
||||||
|
ftp_code = -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(Curl_GetFTPResponse(&nread, conn, &ftp_code) != CURLE_OK)
|
||||||
|
ftp_code = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)nread; /* Unused */
|
||||||
|
va_end(args);
|
||||||
|
return ftp_code;
|
||||||
|
}
|
||||||
|
|
||||||
/* Read |len| from the socket |fd| and store it in |to|. Return a
|
/* Read |len| from the socket |fd| and store it in |to|. Return a
|
||||||
CURLcode saying whether an error occured or CURLE_OK if |len| was read. */
|
CURLcode saying whether an error occured or CURLE_OK if |len| was read. */
|
||||||
@@ -416,66 +437,76 @@ Curl_sec_request_prot(struct connectdata *conn, const char *level)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static CURLcode choose_mech(struct connectdata *conn)
|
||||||
Curl_sec_login(struct connectdata *conn)
|
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
const struct Curl_sec_client_mech * const *m;
|
|
||||||
ssize_t nread;
|
|
||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
int ftpcode;
|
const struct Curl_sec_client_mech * const *mech;
|
||||||
|
void *tmp_allocation;
|
||||||
|
const char *mech_name;
|
||||||
|
|
||||||
for(m = mechs; *m && (*m)->name; m++) {
|
for(mech = mechs; (*mech); ++mech) {
|
||||||
void *tmp;
|
mech_name = (*mech)->name;
|
||||||
|
/* We have no mechanism with a NULL name but keep this check */
|
||||||
tmp = realloc(conn->app_data, (*m)->size);
|
DEBUGASSERT(mech_name != NULL);
|
||||||
if(tmp == NULL) {
|
if(mech_name == NULL) {
|
||||||
failf (data, "realloc %u failed", (*m)->size);
|
infof(data, "Skipping mechanism with empty name (%p)", mech);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
conn->app_data = tmp;
|
|
||||||
|
|
||||||
if((*m)->init && (*(*m)->init)(conn->app_data) != 0) {
|
|
||||||
infof(data, "Skipping %s...\n", (*m)->name);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
infof(data, "Trying %s...\n", (*m)->name);
|
tmp_allocation = realloc(conn->app_data, (*mech)->size);
|
||||||
|
if(tmp_allocation == NULL) {
|
||||||
|
failf(data, "Failed realloc of size %u", (*mech)->size);
|
||||||
|
mech = NULL;
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
conn->app_data = tmp_allocation;
|
||||||
|
|
||||||
if(Curl_ftpsendf(conn, "AUTH %s", (*m)->name))
|
if((*mech)->init) {
|
||||||
return -1;
|
ret = (*mech)->init(conn);
|
||||||
|
if(ret != 0) {
|
||||||
|
infof(data, "Failed initialization for %s. Skipping it.", mech_name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(Curl_GetFTPResponse(&nread, conn, &ftpcode))
|
infof(data, "Trying mechanism %s...", mech_name);
|
||||||
return -1;
|
ret = ftp_send_command(conn, "AUTH %s", mech_name);
|
||||||
|
if(ret < 0)
|
||||||
|
/* FIXME: This error is too generic but it is OK for now. */
|
||||||
|
return CURLE_COULDNT_CONNECT;
|
||||||
|
|
||||||
if(conn->data->state.buffer[0] != '3'){
|
if(ret/100 != 3) {
|
||||||
switch(ftpcode) {
|
switch(ret) {
|
||||||
case 504:
|
case 504:
|
||||||
infof(data,
|
infof(data, "Mechanism %s is not supported by the server (server "
|
||||||
"%s is not supported by the server.\n", (*m)->name);
|
"returned ftp code: 504).", mech_name);
|
||||||
break;
|
break;
|
||||||
case 534:
|
case 534:
|
||||||
infof(data, "%s rejected as security mechanism.\n", (*m)->name);
|
infof(data, "Mechanism %s was rejected by the server (server returned "
|
||||||
|
"ftp code: 534).", mech_name);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if(conn->data->state.buffer[0] == '5') {
|
if(ret/100 == 5) {
|
||||||
infof(data, "The server doesn't support the FTP "
|
infof(data, "The server does not support the security extensions.");
|
||||||
"security extensions.\n");
|
return CURLE_USE_SSL_FAILED;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = (*(*m)->auth)(conn->app_data, conn);
|
/* Authenticate */
|
||||||
|
ret = ((*mech)->auth)(conn->app_data, conn);
|
||||||
|
|
||||||
if(ret == AUTH_CONTINUE)
|
if(ret == AUTH_CONTINUE)
|
||||||
continue;
|
continue;
|
||||||
else if(ret != AUTH_OK) {
|
else if(ret != AUTH_OK) {
|
||||||
/* mechanism is supposed to output error string */
|
/* Mechanism has dumped the error to stderr, don't error here. */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
conn->mech = *m;
|
DEBUGASSERT(ret == AUTH_OK);
|
||||||
|
|
||||||
|
conn->mech = *mech;
|
||||||
conn->sec_complete = 1;
|
conn->sec_complete = 1;
|
||||||
if (conn->data_prot != prot_clear) {
|
if (conn->data_prot != prot_clear) {
|
||||||
conn->recv[FIRSTSOCKET] = sec_read;
|
conn->recv[FIRSTSOCKET] = sec_read;
|
||||||
@@ -490,9 +521,17 @@ Curl_sec_login(struct connectdata *conn)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return *m == NULL;
|
return mech != NULL ? CURLE_OK : CURLE_FAILED_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Curl_sec_login(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
CURLcode code = choose_mech(conn);
|
||||||
|
return code == CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Curl_sec_end(struct connectdata *conn)
|
Curl_sec_end(struct connectdata *conn)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user