mirror of
https://github.com/curl/curl.git
synced 2026-01-26 15:03:21 +00:00
lib: reorder protocol functions to avoid forward declarations (ssh)
Move protocol handler table to the end of sources, rearrange static functions in reverse dependency order as necessary. Closes #20290
This commit is contained in:
parent
7d2c65e6ee
commit
f6a83894eb
@ -84,100 +84,6 @@
|
||||
#define SSH_S_IFLNK 0120000
|
||||
#endif
|
||||
|
||||
/* Local functions: */
|
||||
static CURLcode myssh_connect(struct Curl_easy *data, bool *done);
|
||||
static CURLcode myssh_multi_statemach(struct Curl_easy *data,
|
||||
bool *done);
|
||||
static CURLcode myssh_do_it(struct Curl_easy *data, bool *done);
|
||||
|
||||
static CURLcode scp_done(struct Curl_easy *data,
|
||||
CURLcode, bool premature);
|
||||
static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done);
|
||||
static CURLcode scp_disconnect(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
bool dead_connection);
|
||||
|
||||
static CURLcode sftp_done(struct Curl_easy *data,
|
||||
CURLcode, bool premature);
|
||||
static CURLcode sftp_doing(struct Curl_easy *data,
|
||||
bool *dophase_done);
|
||||
static CURLcode sftp_disconnect(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
bool dead);
|
||||
static CURLcode sftp_perform(struct Curl_easy *data,
|
||||
bool *connected,
|
||||
bool *dophase_done);
|
||||
|
||||
static CURLcode myssh_pollset(struct Curl_easy *data,
|
||||
struct easy_pollset *ps);
|
||||
static void myssh_block2waitfor(struct connectdata *conn,
|
||||
struct ssh_conn *sshc,
|
||||
bool block);
|
||||
|
||||
static CURLcode myssh_setup_connection(struct Curl_easy *data,
|
||||
struct connectdata *conn);
|
||||
static void sshc_cleanup(struct ssh_conn *sshc);
|
||||
|
||||
/*
|
||||
* SCP protocol handler.
|
||||
*/
|
||||
|
||||
const struct Curl_handler Curl_handler_scp = {
|
||||
"SCP", /* scheme */
|
||||
myssh_setup_connection, /* setup_connection */
|
||||
myssh_do_it, /* do_it */
|
||||
scp_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
myssh_connect, /* connect_it */
|
||||
myssh_multi_statemach, /* connecting */
|
||||
scp_doing, /* doing */
|
||||
myssh_pollset, /* proto_pollset */
|
||||
myssh_pollset, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
myssh_pollset, /* perform_pollset */
|
||||
scp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_SSH, /* defport */
|
||||
CURLPROTO_SCP, /* protocol */
|
||||
CURLPROTO_SCP, /* family */
|
||||
PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | /* flags */
|
||||
PROTOPT_NOURLQUERY | PROTOPT_CONN_REUSE
|
||||
};
|
||||
|
||||
/*
|
||||
* SFTP protocol handler.
|
||||
*/
|
||||
|
||||
const struct Curl_handler Curl_handler_sftp = {
|
||||
"SFTP", /* scheme */
|
||||
myssh_setup_connection, /* setup_connection */
|
||||
myssh_do_it, /* do_it */
|
||||
sftp_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
myssh_connect, /* connect_it */
|
||||
myssh_multi_statemach, /* connecting */
|
||||
sftp_doing, /* doing */
|
||||
myssh_pollset, /* proto_pollset */
|
||||
myssh_pollset, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
myssh_pollset, /* perform_pollset */
|
||||
sftp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_SSH, /* defport */
|
||||
CURLPROTO_SFTP, /* protocol */
|
||||
CURLPROTO_SFTP, /* family */
|
||||
PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | /* flags */
|
||||
PROTOPT_NOURLQUERY | PROTOPT_CONN_REUSE
|
||||
};
|
||||
|
||||
static CURLcode sftp_error_to_CURLE(int err)
|
||||
{
|
||||
switch(err) {
|
||||
@ -876,6 +782,22 @@ static void myssh_state_init(struct Curl_easy *data,
|
||||
myssh_to(data, sshc, SSH_S_STARTUP);
|
||||
}
|
||||
|
||||
static void myssh_block2waitfor(struct connectdata *conn,
|
||||
struct ssh_conn *sshc,
|
||||
bool block)
|
||||
{
|
||||
(void)conn;
|
||||
if(block) {
|
||||
int dir = ssh_get_poll_flags(sshc->ssh_session);
|
||||
/* translate the libssh define bits into our own bit defines */
|
||||
sshc->waitfor =
|
||||
((dir & SSH_READ_PENDING) ? KEEP_RECV : 0) |
|
||||
((dir & SSH_WRITE_PENDING) ? KEEP_SEND : 0);
|
||||
}
|
||||
else
|
||||
sshc->waitfor = 0;
|
||||
}
|
||||
|
||||
static int myssh_in_S_STARTUP(struct Curl_easy *data,
|
||||
struct ssh_conn *sshc)
|
||||
{
|
||||
@ -1957,6 +1879,62 @@ static int myssh_in_TRANS_INIT(struct Curl_easy *data, struct ssh_conn *sshc,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void sshc_cleanup(struct ssh_conn *sshc)
|
||||
{
|
||||
if(sshc->initialised) {
|
||||
if(sshc->sftp_file) {
|
||||
sftp_close(sshc->sftp_file);
|
||||
sshc->sftp_file = NULL;
|
||||
}
|
||||
if(sshc->sftp_session) {
|
||||
sftp_free(sshc->sftp_session);
|
||||
sshc->sftp_session = NULL;
|
||||
}
|
||||
if(sshc->ssh_session) {
|
||||
ssh_free(sshc->ssh_session);
|
||||
sshc->ssh_session = NULL;
|
||||
}
|
||||
|
||||
/* worst-case scenario cleanup */
|
||||
DEBUGASSERT(sshc->ssh_session == NULL);
|
||||
DEBUGASSERT(sshc->scp_session == NULL);
|
||||
|
||||
if(sshc->readdir_tmp) {
|
||||
ssh_string_free_char(sshc->readdir_tmp);
|
||||
sshc->readdir_tmp = NULL;
|
||||
}
|
||||
if(sshc->quote_attrs) {
|
||||
sftp_attributes_free(sshc->quote_attrs);
|
||||
sshc->quote_attrs = NULL;
|
||||
}
|
||||
if(sshc->readdir_attrs) {
|
||||
sftp_attributes_free(sshc->readdir_attrs);
|
||||
sshc->readdir_attrs = NULL;
|
||||
}
|
||||
if(sshc->readdir_link_attrs) {
|
||||
sftp_attributes_free(sshc->readdir_link_attrs);
|
||||
sshc->readdir_link_attrs = NULL;
|
||||
}
|
||||
if(sshc->privkey) {
|
||||
ssh_key_free(sshc->privkey);
|
||||
sshc->privkey = NULL;
|
||||
}
|
||||
if(sshc->pubkey) {
|
||||
ssh_key_free(sshc->pubkey);
|
||||
sshc->pubkey = NULL;
|
||||
}
|
||||
|
||||
Curl_safefree(sshc->rsa_pub);
|
||||
Curl_safefree(sshc->rsa);
|
||||
Curl_safefree(sshc->quote_path1);
|
||||
Curl_safefree(sshc->quote_path2);
|
||||
curlx_dyn_free(&sshc->readdir_buf);
|
||||
Curl_safefree(sshc->readdir_linkPath);
|
||||
SSH_STRING_FREE_CHAR(sshc->homedir);
|
||||
sshc->initialised = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ssh_statemach_act() runs the SSH state machine as far as it can without
|
||||
* blocking and without reaching the end. The data the pointer 'block' points
|
||||
@ -2401,22 +2379,6 @@ static CURLcode myssh_pollset(struct Curl_easy *data,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static void myssh_block2waitfor(struct connectdata *conn,
|
||||
struct ssh_conn *sshc,
|
||||
bool block)
|
||||
{
|
||||
(void)conn;
|
||||
if(block) {
|
||||
int dir = ssh_get_poll_flags(sshc->ssh_session);
|
||||
/* translate the libssh define bits into our own bit defines */
|
||||
sshc->waitfor =
|
||||
((dir & SSH_READ_PENDING) ? KEEP_RECV : 0) |
|
||||
((dir & SSH_WRITE_PENDING) ? KEEP_SEND : 0);
|
||||
}
|
||||
else
|
||||
sshc->waitfor = 0;
|
||||
}
|
||||
|
||||
/* called repeatedly until done from multi.c */
|
||||
static CURLcode myssh_multi_statemach(struct Curl_easy *data,
|
||||
bool *done)
|
||||
@ -2692,89 +2654,6 @@ static CURLcode scp_perform(struct Curl_easy *data,
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode myssh_do_it(struct Curl_easy *data, bool *done)
|
||||
{
|
||||
CURLcode result;
|
||||
bool connected = FALSE;
|
||||
struct connectdata *conn = data->conn;
|
||||
struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
|
||||
|
||||
*done = FALSE; /* default to false */
|
||||
if(!sshc)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
data->req.size = -1; /* make sure this is unknown at this point */
|
||||
|
||||
sshc->actualcode = CURLE_OK; /* reset error code */
|
||||
sshc->secondCreateDirs = 0; /* reset the create directory attempt state
|
||||
variable */
|
||||
|
||||
Curl_pgrsReset(data);
|
||||
|
||||
if(conn->handler->protocol & CURLPROTO_SCP)
|
||||
result = scp_perform(data, &connected, done);
|
||||
else
|
||||
result = sftp_perform(data, &connected, done);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void sshc_cleanup(struct ssh_conn *sshc)
|
||||
{
|
||||
if(sshc->initialised) {
|
||||
if(sshc->sftp_file) {
|
||||
sftp_close(sshc->sftp_file);
|
||||
sshc->sftp_file = NULL;
|
||||
}
|
||||
if(sshc->sftp_session) {
|
||||
sftp_free(sshc->sftp_session);
|
||||
sshc->sftp_session = NULL;
|
||||
}
|
||||
if(sshc->ssh_session) {
|
||||
ssh_free(sshc->ssh_session);
|
||||
sshc->ssh_session = NULL;
|
||||
}
|
||||
|
||||
/* worst-case scenario cleanup */
|
||||
DEBUGASSERT(sshc->ssh_session == NULL);
|
||||
DEBUGASSERT(sshc->scp_session == NULL);
|
||||
|
||||
if(sshc->readdir_tmp) {
|
||||
ssh_string_free_char(sshc->readdir_tmp);
|
||||
sshc->readdir_tmp = NULL;
|
||||
}
|
||||
if(sshc->quote_attrs) {
|
||||
sftp_attributes_free(sshc->quote_attrs);
|
||||
sshc->quote_attrs = NULL;
|
||||
}
|
||||
if(sshc->readdir_attrs) {
|
||||
sftp_attributes_free(sshc->readdir_attrs);
|
||||
sshc->readdir_attrs = NULL;
|
||||
}
|
||||
if(sshc->readdir_link_attrs) {
|
||||
sftp_attributes_free(sshc->readdir_link_attrs);
|
||||
sshc->readdir_link_attrs = NULL;
|
||||
}
|
||||
if(sshc->privkey) {
|
||||
ssh_key_free(sshc->privkey);
|
||||
sshc->privkey = NULL;
|
||||
}
|
||||
if(sshc->pubkey) {
|
||||
ssh_key_free(sshc->pubkey);
|
||||
sshc->pubkey = NULL;
|
||||
}
|
||||
|
||||
Curl_safefree(sshc->rsa_pub);
|
||||
Curl_safefree(sshc->rsa);
|
||||
Curl_safefree(sshc->quote_path1);
|
||||
Curl_safefree(sshc->quote_path2);
|
||||
curlx_dyn_free(&sshc->readdir_buf);
|
||||
Curl_safefree(sshc->readdir_linkPath);
|
||||
SSH_STRING_FREE_CHAR(sshc->homedir);
|
||||
sshc->initialised = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* BLOCKING, but the function is using the state machine so the only reason
|
||||
this is still blocking is that the multi interface code has no support for
|
||||
disconnecting operations that takes a while */
|
||||
@ -3136,6 +3015,33 @@ static CURLcode sftp_recv(struct Curl_easy *data, int sockindex,
|
||||
}
|
||||
}
|
||||
|
||||
static CURLcode myssh_do_it(struct Curl_easy *data, bool *done)
|
||||
{
|
||||
CURLcode result;
|
||||
bool connected = FALSE;
|
||||
struct connectdata *conn = data->conn;
|
||||
struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
|
||||
|
||||
*done = FALSE; /* default to false */
|
||||
if(!sshc)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
data->req.size = -1; /* make sure this is unknown at this point */
|
||||
|
||||
sshc->actualcode = CURLE_OK; /* reset error code */
|
||||
sshc->secondCreateDirs = 0; /* reset the create directory attempt state
|
||||
variable */
|
||||
|
||||
Curl_pgrsReset(data);
|
||||
|
||||
if(conn->handler->protocol & CURLPROTO_SCP)
|
||||
result = scp_perform(data, &connected, done);
|
||||
else
|
||||
result = sftp_perform(data, &connected, done);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_ssh_init(void)
|
||||
{
|
||||
if(ssh_init()) {
|
||||
@ -3155,4 +3061,62 @@ void Curl_ssh_version(char *buffer, size_t buflen)
|
||||
(void)curl_msnprintf(buffer, buflen, "libssh/%s", ssh_version(0));
|
||||
}
|
||||
|
||||
/*
|
||||
* SCP protocol handler.
|
||||
*/
|
||||
const struct Curl_handler Curl_handler_scp = {
|
||||
"SCP", /* scheme */
|
||||
myssh_setup_connection, /* setup_connection */
|
||||
myssh_do_it, /* do_it */
|
||||
scp_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
myssh_connect, /* connect_it */
|
||||
myssh_multi_statemach, /* connecting */
|
||||
scp_doing, /* doing */
|
||||
myssh_pollset, /* proto_pollset */
|
||||
myssh_pollset, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
myssh_pollset, /* perform_pollset */
|
||||
scp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_SSH, /* defport */
|
||||
CURLPROTO_SCP, /* protocol */
|
||||
CURLPROTO_SCP, /* family */
|
||||
PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | /* flags */
|
||||
PROTOPT_NOURLQUERY | PROTOPT_CONN_REUSE
|
||||
};
|
||||
|
||||
/*
|
||||
* SFTP protocol handler.
|
||||
*/
|
||||
const struct Curl_handler Curl_handler_sftp = {
|
||||
"SFTP", /* scheme */
|
||||
myssh_setup_connection, /* setup_connection */
|
||||
myssh_do_it, /* do_it */
|
||||
sftp_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
myssh_connect, /* connect_it */
|
||||
myssh_multi_statemach, /* connecting */
|
||||
sftp_doing, /* doing */
|
||||
myssh_pollset, /* proto_pollset */
|
||||
myssh_pollset, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
myssh_pollset, /* perform_pollset */
|
||||
sftp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_SSH, /* defport */
|
||||
CURLPROTO_SFTP, /* protocol */
|
||||
CURLPROTO_SFTP, /* family */
|
||||
PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | /* flags */
|
||||
PROTOPT_NOURLQUERY | PROTOPT_CONN_REUSE
|
||||
};
|
||||
|
||||
#endif /* USE_LIBSSH */
|
||||
|
||||
@ -59,92 +59,71 @@
|
||||
#include "../curlx/strparse.h"
|
||||
#include "../curlx/base64.h" /* for base64 encoding/decoding */
|
||||
|
||||
/* Local functions: */
|
||||
static const char *sftp_libssh2_strerror(unsigned long err);
|
||||
static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc);
|
||||
static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc);
|
||||
static LIBSSH2_FREE_FUNC(my_libssh2_free);
|
||||
static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data,
|
||||
struct ssh_conn *sshc);
|
||||
static CURLcode ssh_connect(struct Curl_easy *data, bool *done);
|
||||
static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done);
|
||||
static CURLcode ssh_do(struct Curl_easy *data, bool *done);
|
||||
static CURLcode scp_done(struct Curl_easy *data, CURLcode c, bool premature);
|
||||
static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done);
|
||||
static CURLcode scp_disconnect(struct Curl_easy *data,
|
||||
struct connectdata *conn, bool dead_connection);
|
||||
static CURLcode sftp_done(struct Curl_easy *data, CURLcode, bool premature);
|
||||
static CURLcode sftp_doing(struct Curl_easy *data, bool *dophase_done);
|
||||
static CURLcode sftp_disconnect(struct Curl_easy *data,
|
||||
struct connectdata *conn, bool dead);
|
||||
static CURLcode sftp_perform(struct Curl_easy *data, bool *connected,
|
||||
bool *dophase_done);
|
||||
static CURLcode ssh_pollset(struct Curl_easy *data,
|
||||
struct easy_pollset *ps);
|
||||
static CURLcode ssh_setup_connection(struct Curl_easy *data,
|
||||
struct connectdata *conn);
|
||||
static void ssh_attach(struct Curl_easy *data, struct connectdata *conn);
|
||||
static CURLcode sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data,
|
||||
bool block);
|
||||
/*
|
||||
* SCP protocol handler.
|
||||
*/
|
||||
static const char *sftp_libssh2_strerror(unsigned long err)
|
||||
{
|
||||
switch(err) {
|
||||
case LIBSSH2_FX_NO_SUCH_FILE:
|
||||
return "No such file or directory";
|
||||
|
||||
const struct Curl_handler Curl_handler_scp = {
|
||||
"SCP", /* scheme */
|
||||
ssh_setup_connection, /* setup_connection */
|
||||
ssh_do, /* do_it */
|
||||
scp_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
ssh_connect, /* connect_it */
|
||||
ssh_multi_statemach, /* connecting */
|
||||
scp_doing, /* doing */
|
||||
ssh_pollset, /* proto_pollset */
|
||||
ssh_pollset, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
ssh_pollset, /* perform_pollset */
|
||||
scp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ssh_attach, /* attach */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_SSH, /* defport */
|
||||
CURLPROTO_SCP, /* protocol */
|
||||
CURLPROTO_SCP, /* family */
|
||||
PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | /* flags */
|
||||
PROTOPT_NOURLQUERY | PROTOPT_CONN_REUSE
|
||||
};
|
||||
case LIBSSH2_FX_PERMISSION_DENIED:
|
||||
return "Permission denied";
|
||||
|
||||
/*
|
||||
* SFTP protocol handler.
|
||||
*/
|
||||
case LIBSSH2_FX_FAILURE:
|
||||
return "Operation failed";
|
||||
|
||||
const struct Curl_handler Curl_handler_sftp = {
|
||||
"SFTP", /* scheme */
|
||||
ssh_setup_connection, /* setup_connection */
|
||||
ssh_do, /* do_it */
|
||||
sftp_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
ssh_connect, /* connect_it */
|
||||
ssh_multi_statemach, /* connecting */
|
||||
sftp_doing, /* doing */
|
||||
ssh_pollset, /* proto_pollset */
|
||||
ssh_pollset, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
ssh_pollset, /* perform_pollset */
|
||||
sftp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ssh_attach, /* attach */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_SSH, /* defport */
|
||||
CURLPROTO_SFTP, /* protocol */
|
||||
CURLPROTO_SFTP, /* family */
|
||||
PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | /* flags */
|
||||
PROTOPT_NOURLQUERY | PROTOPT_CONN_REUSE
|
||||
};
|
||||
case LIBSSH2_FX_BAD_MESSAGE:
|
||||
return "Bad message from SFTP server";
|
||||
|
||||
case LIBSSH2_FX_NO_CONNECTION:
|
||||
return "Not connected to SFTP server";
|
||||
|
||||
case LIBSSH2_FX_CONNECTION_LOST:
|
||||
return "Connection to SFTP server lost";
|
||||
|
||||
case LIBSSH2_FX_OP_UNSUPPORTED:
|
||||
return "Operation not supported by SFTP server";
|
||||
|
||||
case LIBSSH2_FX_INVALID_HANDLE:
|
||||
return "Invalid handle";
|
||||
|
||||
case LIBSSH2_FX_NO_SUCH_PATH:
|
||||
return "No such file or directory";
|
||||
|
||||
case LIBSSH2_FX_FILE_ALREADY_EXISTS:
|
||||
return "File already exists";
|
||||
|
||||
case LIBSSH2_FX_WRITE_PROTECT:
|
||||
return "File is write protected";
|
||||
|
||||
case LIBSSH2_FX_NO_MEDIA:
|
||||
return "No media";
|
||||
|
||||
case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM:
|
||||
return "Disk full";
|
||||
|
||||
case LIBSSH2_FX_QUOTA_EXCEEDED:
|
||||
return "User quota exceeded";
|
||||
|
||||
case LIBSSH2_FX_UNKNOWN_PRINCIPLE:
|
||||
return "Unknown principle";
|
||||
|
||||
case LIBSSH2_FX_LOCK_CONFlICT:
|
||||
return "File lock conflict";
|
||||
|
||||
case LIBSSH2_FX_DIR_NOT_EMPTY:
|
||||
return "Directory not empty";
|
||||
|
||||
case LIBSSH2_FX_NOT_A_DIRECTORY:
|
||||
return "Not a directory";
|
||||
|
||||
case LIBSSH2_FX_INVALID_FILENAME:
|
||||
return "Invalid filename";
|
||||
|
||||
case LIBSSH2_FX_LINK_LOOP:
|
||||
return "Link points to itself";
|
||||
}
|
||||
return "Unknown error in libssh2";
|
||||
}
|
||||
|
||||
static void kbd_callback(const char *name, int name_len,
|
||||
const char *instruction, int instruction_len,
|
||||
@ -2573,13 +2552,112 @@ static CURLcode ssh_state_session_disconnect(struct Curl_easy *data,
|
||||
myssh_state(data, sshc, SSH_SESSION_FREE);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data,
|
||||
bool block)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if(sshc->kh) {
|
||||
libssh2_knownhost_free(sshc->kh);
|
||||
sshc->kh = NULL;
|
||||
}
|
||||
|
||||
if(sshc->ssh_agent) {
|
||||
rc = libssh2_agent_disconnect(sshc->ssh_agent);
|
||||
if((rc < 0) && data) {
|
||||
char *err_msg = NULL;
|
||||
(void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0);
|
||||
infof(data, "Failed to disconnect from libssh2 agent: %d %s",
|
||||
rc, err_msg);
|
||||
}
|
||||
if(!block && (rc == LIBSSH2_ERROR_EAGAIN))
|
||||
return CURLE_AGAIN;
|
||||
|
||||
libssh2_agent_free(sshc->ssh_agent);
|
||||
sshc->ssh_agent = NULL;
|
||||
|
||||
/* NB: there is no need to free identities, they are part of internal
|
||||
agent stuff */
|
||||
sshc->sshagent_identity = NULL;
|
||||
sshc->sshagent_prev_identity = NULL;
|
||||
}
|
||||
|
||||
if(sshc->sftp_handle) {
|
||||
rc = libssh2_sftp_close(sshc->sftp_handle);
|
||||
if((rc < 0) && data) {
|
||||
char *err_msg = NULL;
|
||||
(void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0);
|
||||
infof(data, "Failed to close libssh2 file: %d %s", rc, err_msg);
|
||||
}
|
||||
if(!block && (rc == LIBSSH2_ERROR_EAGAIN))
|
||||
return CURLE_AGAIN;
|
||||
|
||||
sshc->sftp_handle = NULL;
|
||||
}
|
||||
|
||||
if(sshc->ssh_channel) {
|
||||
rc = libssh2_channel_free(sshc->ssh_channel);
|
||||
if((rc < 0) && data) {
|
||||
char *err_msg = NULL;
|
||||
(void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0);
|
||||
infof(data, "Failed to free libssh2 scp subsystem: %d %s", rc, err_msg);
|
||||
}
|
||||
if(!block && (rc == LIBSSH2_ERROR_EAGAIN))
|
||||
return CURLE_AGAIN;
|
||||
|
||||
sshc->ssh_channel = NULL;
|
||||
}
|
||||
|
||||
if(sshc->sftp_session) {
|
||||
rc = libssh2_sftp_shutdown(sshc->sftp_session);
|
||||
if((rc < 0) && data) {
|
||||
char *err_msg = NULL;
|
||||
(void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0);
|
||||
infof(data, "Failed to stop libssh2 sftp subsystem: %d %s", rc, err_msg);
|
||||
}
|
||||
if(!block && (rc == LIBSSH2_ERROR_EAGAIN))
|
||||
return CURLE_AGAIN;
|
||||
|
||||
sshc->sftp_session = NULL;
|
||||
}
|
||||
|
||||
if(sshc->ssh_session) {
|
||||
rc = libssh2_session_free(sshc->ssh_session);
|
||||
if((rc < 0) && data) {
|
||||
char *err_msg = NULL;
|
||||
(void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0);
|
||||
infof(data, "Failed to free libssh2 session: %d %s", rc, err_msg);
|
||||
}
|
||||
if(!block && (rc == LIBSSH2_ERROR_EAGAIN))
|
||||
return CURLE_AGAIN;
|
||||
|
||||
sshc->ssh_session = NULL;
|
||||
}
|
||||
|
||||
/* worst-case scenario cleanup */
|
||||
DEBUGASSERT(sshc->ssh_session == NULL);
|
||||
DEBUGASSERT(sshc->ssh_channel == NULL);
|
||||
DEBUGASSERT(sshc->sftp_session == NULL);
|
||||
DEBUGASSERT(sshc->sftp_handle == NULL);
|
||||
DEBUGASSERT(sshc->kh == NULL);
|
||||
DEBUGASSERT(sshc->ssh_agent == NULL);
|
||||
|
||||
Curl_safefree(sshc->rsa_pub);
|
||||
Curl_safefree(sshc->rsa);
|
||||
Curl_safefree(sshc->quote_path1);
|
||||
Curl_safefree(sshc->quote_path2);
|
||||
Curl_safefree(sshc->homedir);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* ssh_statemachine() runs the SSH state machine as far as it can without
|
||||
* blocking and without reaching the end. The data the pointer 'block' points
|
||||
* to will be set to TRUE if the libssh2 function returns LIBSSH2_ERROR_EAGAIN
|
||||
* meaning it wants to be called again when the socket is ready
|
||||
*/
|
||||
|
||||
static CURLcode ssh_statemachine(struct Curl_easy *data,
|
||||
struct ssh_conn *sshc,
|
||||
struct SSHPROTO *sshp,
|
||||
@ -3494,135 +3572,6 @@ static CURLcode scp_doing(struct Curl_easy *data,
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* The DO function is generic for both protocols. There was previously two
|
||||
* separate ones but this way means less duplicated code.
|
||||
*/
|
||||
|
||||
static CURLcode ssh_do(struct Curl_easy *data, bool *done)
|
||||
{
|
||||
CURLcode result;
|
||||
bool connected = FALSE;
|
||||
struct connectdata *conn = data->conn;
|
||||
struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
|
||||
|
||||
*done = FALSE; /* default to false */
|
||||
if(!sshc)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
data->req.size = -1; /* make sure this is unknown at this point */
|
||||
sshc->secondCreateDirs = 0; /* reset the create directory attempt state
|
||||
variable */
|
||||
|
||||
Curl_pgrsReset(data);
|
||||
|
||||
if(conn->handler->protocol & CURLPROTO_SCP)
|
||||
result = scp_perform(data, &connected, done);
|
||||
else
|
||||
result = sftp_perform(data, &connected, done);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data,
|
||||
bool block)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if(sshc->kh) {
|
||||
libssh2_knownhost_free(sshc->kh);
|
||||
sshc->kh = NULL;
|
||||
}
|
||||
|
||||
if(sshc->ssh_agent) {
|
||||
rc = libssh2_agent_disconnect(sshc->ssh_agent);
|
||||
if((rc < 0) && data) {
|
||||
char *err_msg = NULL;
|
||||
(void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0);
|
||||
infof(data, "Failed to disconnect from libssh2 agent: %d %s",
|
||||
rc, err_msg);
|
||||
}
|
||||
if(!block && (rc == LIBSSH2_ERROR_EAGAIN))
|
||||
return CURLE_AGAIN;
|
||||
|
||||
libssh2_agent_free(sshc->ssh_agent);
|
||||
sshc->ssh_agent = NULL;
|
||||
|
||||
/* NB: there is no need to free identities, they are part of internal
|
||||
agent stuff */
|
||||
sshc->sshagent_identity = NULL;
|
||||
sshc->sshagent_prev_identity = NULL;
|
||||
}
|
||||
|
||||
if(sshc->sftp_handle) {
|
||||
rc = libssh2_sftp_close(sshc->sftp_handle);
|
||||
if((rc < 0) && data) {
|
||||
char *err_msg = NULL;
|
||||
(void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0);
|
||||
infof(data, "Failed to close libssh2 file: %d %s", rc, err_msg);
|
||||
}
|
||||
if(!block && (rc == LIBSSH2_ERROR_EAGAIN))
|
||||
return CURLE_AGAIN;
|
||||
|
||||
sshc->sftp_handle = NULL;
|
||||
}
|
||||
|
||||
if(sshc->ssh_channel) {
|
||||
rc = libssh2_channel_free(sshc->ssh_channel);
|
||||
if((rc < 0) && data) {
|
||||
char *err_msg = NULL;
|
||||
(void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0);
|
||||
infof(data, "Failed to free libssh2 scp subsystem: %d %s", rc, err_msg);
|
||||
}
|
||||
if(!block && (rc == LIBSSH2_ERROR_EAGAIN))
|
||||
return CURLE_AGAIN;
|
||||
|
||||
sshc->ssh_channel = NULL;
|
||||
}
|
||||
|
||||
if(sshc->sftp_session) {
|
||||
rc = libssh2_sftp_shutdown(sshc->sftp_session);
|
||||
if((rc < 0) && data) {
|
||||
char *err_msg = NULL;
|
||||
(void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0);
|
||||
infof(data, "Failed to stop libssh2 sftp subsystem: %d %s", rc, err_msg);
|
||||
}
|
||||
if(!block && (rc == LIBSSH2_ERROR_EAGAIN))
|
||||
return CURLE_AGAIN;
|
||||
|
||||
sshc->sftp_session = NULL;
|
||||
}
|
||||
|
||||
if(sshc->ssh_session) {
|
||||
rc = libssh2_session_free(sshc->ssh_session);
|
||||
if((rc < 0) && data) {
|
||||
char *err_msg = NULL;
|
||||
(void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0);
|
||||
infof(data, "Failed to free libssh2 session: %d %s", rc, err_msg);
|
||||
}
|
||||
if(!block && (rc == LIBSSH2_ERROR_EAGAIN))
|
||||
return CURLE_AGAIN;
|
||||
|
||||
sshc->ssh_session = NULL;
|
||||
}
|
||||
|
||||
/* worst-case scenario cleanup */
|
||||
DEBUGASSERT(sshc->ssh_session == NULL);
|
||||
DEBUGASSERT(sshc->ssh_channel == NULL);
|
||||
DEBUGASSERT(sshc->sftp_session == NULL);
|
||||
DEBUGASSERT(sshc->sftp_handle == NULL);
|
||||
DEBUGASSERT(sshc->kh == NULL);
|
||||
DEBUGASSERT(sshc->ssh_agent == NULL);
|
||||
|
||||
Curl_safefree(sshc->rsa_pub);
|
||||
Curl_safefree(sshc->rsa);
|
||||
Curl_safefree(sshc->quote_path1);
|
||||
Curl_safefree(sshc->quote_path2);
|
||||
Curl_safefree(sshc->homedir);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* BLOCKING, but the function is using the state machine so the only reason
|
||||
this is still blocking is that the multi interface code has no support for
|
||||
disconnecting operations that takes a while */
|
||||
@ -3897,70 +3846,33 @@ static CURLcode sftp_recv(struct Curl_easy *data, int sockindex,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static const char *sftp_libssh2_strerror(unsigned long err)
|
||||
/*
|
||||
* The DO function is generic for both protocols. There was previously two
|
||||
* separate ones but this way means less duplicated code.
|
||||
*/
|
||||
static CURLcode ssh_do(struct Curl_easy *data, bool *done)
|
||||
{
|
||||
switch(err) {
|
||||
case LIBSSH2_FX_NO_SUCH_FILE:
|
||||
return "No such file or directory";
|
||||
CURLcode result;
|
||||
bool connected = FALSE;
|
||||
struct connectdata *conn = data->conn;
|
||||
struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
|
||||
|
||||
case LIBSSH2_FX_PERMISSION_DENIED:
|
||||
return "Permission denied";
|
||||
*done = FALSE; /* default to false */
|
||||
if(!sshc)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
case LIBSSH2_FX_FAILURE:
|
||||
return "Operation failed";
|
||||
data->req.size = -1; /* make sure this is unknown at this point */
|
||||
sshc->secondCreateDirs = 0; /* reset the create directory attempt state
|
||||
variable */
|
||||
|
||||
case LIBSSH2_FX_BAD_MESSAGE:
|
||||
return "Bad message from SFTP server";
|
||||
Curl_pgrsReset(data);
|
||||
|
||||
case LIBSSH2_FX_NO_CONNECTION:
|
||||
return "Not connected to SFTP server";
|
||||
if(conn->handler->protocol & CURLPROTO_SCP)
|
||||
result = scp_perform(data, &connected, done);
|
||||
else
|
||||
result = sftp_perform(data, &connected, done);
|
||||
|
||||
case LIBSSH2_FX_CONNECTION_LOST:
|
||||
return "Connection to SFTP server lost";
|
||||
|
||||
case LIBSSH2_FX_OP_UNSUPPORTED:
|
||||
return "Operation not supported by SFTP server";
|
||||
|
||||
case LIBSSH2_FX_INVALID_HANDLE:
|
||||
return "Invalid handle";
|
||||
|
||||
case LIBSSH2_FX_NO_SUCH_PATH:
|
||||
return "No such file or directory";
|
||||
|
||||
case LIBSSH2_FX_FILE_ALREADY_EXISTS:
|
||||
return "File already exists";
|
||||
|
||||
case LIBSSH2_FX_WRITE_PROTECT:
|
||||
return "File is write protected";
|
||||
|
||||
case LIBSSH2_FX_NO_MEDIA:
|
||||
return "No media";
|
||||
|
||||
case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM:
|
||||
return "Disk full";
|
||||
|
||||
case LIBSSH2_FX_QUOTA_EXCEEDED:
|
||||
return "User quota exceeded";
|
||||
|
||||
case LIBSSH2_FX_UNKNOWN_PRINCIPLE:
|
||||
return "Unknown principle";
|
||||
|
||||
case LIBSSH2_FX_LOCK_CONFlICT:
|
||||
return "File lock conflict";
|
||||
|
||||
case LIBSSH2_FX_DIR_NOT_EMPTY:
|
||||
return "Directory not empty";
|
||||
|
||||
case LIBSSH2_FX_NOT_A_DIRECTORY:
|
||||
return "Not a directory";
|
||||
|
||||
case LIBSSH2_FX_INVALID_FILENAME:
|
||||
return "Invalid filename";
|
||||
|
||||
case LIBSSH2_FX_LINK_LOOP:
|
||||
return "Link points to itself";
|
||||
}
|
||||
return "Unknown error in libssh2";
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_ssh_init(void)
|
||||
@ -3999,4 +3911,63 @@ static void ssh_attach(struct Curl_easy *data, struct connectdata *conn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* SCP protocol handler.
|
||||
*/
|
||||
const struct Curl_handler Curl_handler_scp = {
|
||||
"SCP", /* scheme */
|
||||
ssh_setup_connection, /* setup_connection */
|
||||
ssh_do, /* do_it */
|
||||
scp_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
ssh_connect, /* connect_it */
|
||||
ssh_multi_statemach, /* connecting */
|
||||
scp_doing, /* doing */
|
||||
ssh_pollset, /* proto_pollset */
|
||||
ssh_pollset, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
ssh_pollset, /* perform_pollset */
|
||||
scp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ssh_attach, /* attach */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_SSH, /* defport */
|
||||
CURLPROTO_SCP, /* protocol */
|
||||
CURLPROTO_SCP, /* family */
|
||||
PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | /* flags */
|
||||
PROTOPT_NOURLQUERY | PROTOPT_CONN_REUSE
|
||||
};
|
||||
|
||||
/*
|
||||
* SFTP protocol handler.
|
||||
*/
|
||||
const struct Curl_handler Curl_handler_sftp = {
|
||||
"SFTP", /* scheme */
|
||||
ssh_setup_connection, /* setup_connection */
|
||||
ssh_do, /* do_it */
|
||||
sftp_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
ssh_connect, /* connect_it */
|
||||
ssh_multi_statemach, /* connecting */
|
||||
sftp_doing, /* doing */
|
||||
ssh_pollset, /* proto_pollset */
|
||||
ssh_pollset, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
ssh_pollset, /* perform_pollset */
|
||||
sftp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ssh_attach, /* attach */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_SSH, /* defport */
|
||||
CURLPROTO_SFTP, /* protocol */
|
||||
CURLPROTO_SFTP, /* family */
|
||||
PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | /* flags */
|
||||
PROTOPT_NOURLQUERY | PROTOPT_CONN_REUSE
|
||||
};
|
||||
|
||||
#endif /* USE_LIBSSH2 */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user