lib: reorder protocol functions to avoid forward declarations (ssh)
No binary (build failed)
—
(log yok)
| @@ -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"; |
| - | |
| - | case LIBSSH2_FX_PERMISSION_DENIED: |
| - | return "Permission denied"; |
| - | |
| - | case LIBSSH2_FX_FAILURE: |
| - | return "Operation failed"; |
| - | |
| - | 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"; |
| + | 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_LOCK_CONFlICT: |
| - | return "File lock conflict"; |
| + | *done = FALSE; /* default to false */ |
| + | if(!sshc) |
| + | return CURLE_FAILED_INIT; |
| - | case LIBSSH2_FX_DIR_NOT_EMPTY: |
| - | return "Directory not empty"; |
| + | 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_NOT_A_DIRECTORY: |
| - | return "Not a directory"; |
| + | Curl_pgrsReset(data); |
| - | case LIBSSH2_FX_INVALID_FILENAME: |
| - | return "Invalid filename"; |
| + | if(conn->handler->protocol & CURLPROTO_SCP) |
| + | result = scp_perform(data, &connected, done); |
| + | else |
| + | result = sftp_perform(data, &connected, done); |
| - | 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 */ | |