diff options
-rw-r--r-- | lib/security.c | 115 |
1 files changed, 77 insertions, 38 deletions
diff --git a/lib/security.c b/lib/security.c index 3a3f0e03b..d4bb0b379 100644 --- a/lib/security.c +++ b/lib/security.c @@ -101,6 +101,27 @@ static const struct Curl_sec_client_mech * const mechs[] = { 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 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; } -int -Curl_sec_login(struct connectdata *conn) +static CURLcode choose_mech(struct connectdata *conn) { int ret; - const struct Curl_sec_client_mech * const *m; - ssize_t nread; - struct SessionHandle *data=conn->data; - int ftpcode; - - for(m = mechs; *m && (*m)->name; m++) { - void *tmp; - - tmp = realloc(conn->app_data, (*m)->size); - if(tmp == NULL) { - failf (data, "realloc %u failed", (*m)->size); - return -1; - } - conn->app_data = tmp; - - if((*m)->init && (*(*m)->init)(conn->app_data) != 0) { - infof(data, "Skipping %s...\n", (*m)->name); + struct SessionHandle *data = conn->data; + const struct Curl_sec_client_mech * const *mech; + void *tmp_allocation; + const char *mech_name; + + for(mech = mechs; (*mech); ++mech) { + mech_name = (*mech)->name; + /* We have no mechanism with a NULL name but keep this check */ + DEBUGASSERT(mech_name != NULL); + if(mech_name == NULL) { + infof(data, "Skipping mechanism with empty name (%p)", mech); 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)) - return -1; + if((*mech)->init) { + ret = (*mech)->init(conn); + if(ret != 0) { + infof(data, "Failed initialization for %s. Skipping it.", mech_name); + continue; + } + } - if(Curl_GetFTPResponse(&nread, conn, &ftpcode)) - return -1; + infof(data, "Trying mechanism %s...", mech_name); + 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'){ - switch(ftpcode) { + if(ret/100 != 3) { + switch(ret) { case 504: - infof(data, - "%s is not supported by the server.\n", (*m)->name); + infof(data, "Mechanism %s is not supported by the server (server " + "returned ftp code: 504).", mech_name); break; 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; default: - if(conn->data->state.buffer[0] == '5') { - infof(data, "The server doesn't support the FTP " - "security extensions.\n"); - return -1; + if(ret/100 == 5) { + infof(data, "The server does not support the security extensions."); + return CURLE_USE_SSL_FAILED; } break; } continue; } - ret = (*(*m)->auth)(conn->app_data, conn); + /* Authenticate */ + ret = ((*mech)->auth)(conn->app_data, conn); if(ret == AUTH_CONTINUE) continue; - else if(ret != AUTH_OK){ - /* mechanism is supposed to output error string */ + else if(ret != AUTH_OK) { + /* Mechanism has dumped the error to stderr, don't error here. */ return -1; } - conn->mech = *m; + DEBUGASSERT(ret == AUTH_OK); + + conn->mech = *mech; conn->sec_complete = 1; if (conn->data_prot != prot_clear) { conn->recv[FIRSTSOCKET] = sec_read; @@ -490,9 +521,17 @@ Curl_sec_login(struct connectdata *conn) 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 Curl_sec_end(struct connectdata *conn) { |