summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/vssh/libssh.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/vssh/libssh.c')
-rw-r--r--libs/libcurl/src/vssh/libssh.c1512
1 files changed, 806 insertions, 706 deletions
diff --git a/libs/libcurl/src/vssh/libssh.c b/libs/libcurl/src/vssh/libssh.c
index cb98738fc3..569aa1a996 100644
--- a/libs/libcurl/src/vssh/libssh.c
+++ b/libs/libcurl/src/vssh/libssh.c
@@ -25,7 +25,7 @@
*
***************************************************************************/
-#include "curl_setup.h"
+#include "../curl_setup.h"
#ifdef USE_LIBSSH
@@ -46,29 +46,29 @@
#endif
#include <curl/curl.h>
-#include "urldata.h"
-#include "sendf.h"
-#include "hostip.h"
-#include "progress.h"
-#include "transfer.h"
-#include "escape.h"
-#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "../urldata.h"
+#include "../sendf.h"
+#include "../hostip.h"
+#include "../progress.h"
+#include "../transfer.h"
+#include "../escape.h"
+#include "../http.h" /* for HTTP proxy tunnel stuff */
#include "ssh.h"
-#include "url.h"
-#include "speedcheck.h"
-#include "getinfo.h"
-#include "strdup.h"
-#include "strcase.h"
-#include "vtls/vtls.h"
-#include "cfilters.h"
-#include "connect.h"
-#include "inet_ntop.h"
-#include "parsedate.h" /* for the week day and month names */
-#include "sockaddr.h" /* required for Curl_sockaddr_storage */
-#include "strparse.h"
-#include "multiif.h"
-#include "select.h"
-#include "warnless.h"
+#include "../url.h"
+#include "../speedcheck.h"
+#include "../getinfo.h"
+#include "../strdup.h"
+#include "../strcase.h"
+#include "../vtls/vtls.h"
+#include "../cfilters.h"
+#include "../connect.h"
+#include "../inet_ntop.h"
+#include "../parsedate.h" /* for the week day and month names */
+#include "../sockaddr.h" /* required for Curl_sockaddr_storage */
+#include "../curlx/strparse.h"
+#include "../multiif.h"
+#include "../select.h"
+#include "../curlx/warnless.h"
#include "curl_path.h"
#ifdef HAVE_SYS_STAT_H
@@ -82,9 +82,9 @@
#endif
/* The last 3 #include files should be in this order */
-#include "curl_printf.h"
-#include "curl_memory.h"
-#include "memdebug.h"
+#include "../curl_printf.h"
+#include "../curl_memory.h"
+#include "../memdebug.h"
/* A recent macro provided by libssh. Or make our own. */
#ifndef SSH_STRING_FREE_CHAR
@@ -130,15 +130,19 @@ CURLcode sftp_perform(struct Curl_easy *data,
bool *connected,
bool *dophase_done);
-static void sftp_quote(struct Curl_easy *data);
-static void sftp_quote_stat(struct Curl_easy *data);
+static void sftp_quote(struct Curl_easy *data,
+ struct ssh_conn *sshc,
+ struct SSHPROTO *sshp);
+static void sftp_quote_stat(struct Curl_easy *data, struct ssh_conn *sshc);
static int myssh_getsock(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *sock);
-static void myssh_block2waitfor(struct connectdata *conn, bool block);
+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, struct Curl_easy *data);
+static void sshc_cleanup(struct ssh_conn *sshc);
/*
* SCP protocol handler.
@@ -224,23 +228,23 @@ static CURLcode sftp_error_to_CURLE(int err)
}
#ifndef DEBUGBUILD
-#define state(x,y) mystate(x,y)
+#define myssh_state(x,y,z) myssh_set_state(x,y,z)
#else
-#define state(x,y) mystate(x,y, __LINE__)
+#define myssh_state(x,y,z) myssh_set_state(x,y,z, __LINE__)
#endif
/*
* SSH State machine related code
*/
/* This is the ONLY way to change SSH state! */
-static void mystate(struct Curl_easy *data, sshstate nowstate
+static void myssh_set_state(struct Curl_easy *data,
+ struct ssh_conn *sshc,
+ sshstate nowstate
#ifdef DEBUGBUILD
- , int lineno
+ , int lineno
#endif
)
{
- struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
/* for debug purposes */
static const char *const names[] = {
@@ -313,7 +317,7 @@ static void mystate(struct Curl_easy *data, sshstate nowstate
lineno);
}
#endif
-
+ (void)data;
sshc->state = nowstate;
}
@@ -327,11 +331,9 @@ static void mystate(struct Curl_easy *data, sshstate nowstate
*
* Returns SSH_OK or SSH_ERROR.
*/
-static int myssh_is_known(struct Curl_easy *data)
+static int myssh_is_known(struct Curl_easy *data, struct ssh_conn *sshc)
{
int rc;
- struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
ssh_key pubkey;
size_t hlen;
unsigned char *hash = NULL;
@@ -517,14 +519,14 @@ cleanup:
return rc;
}
-#define MOVE_TO_ERROR_STATE(_r) do { \
- state(data, SSH_SESSION_DISCONNECT); \
- sshc->actualcode = _r; \
- rc = SSH_ERROR; \
+#define MOVE_TO_ERROR_STATE(_r) do { \
+ myssh_state(data, sshc, SSH_SESSION_DISCONNECT); \
+ sshc->actualcode = _r; \
+ rc = SSH_ERROR; \
} while(0)
#define MOVE_TO_SFTP_CLOSE_STATE() do { \
- state(data, SSH_SFTP_CLOSE); \
+ myssh_state(data, sshc, SSH_SFTP_CLOSE); \
sshc->actualcode = \
sftp_error_to_CURLE(sftp_get_error(sshc->sftp_session)); \
rc = SSH_ERROR; \
@@ -533,7 +535,7 @@ cleanup:
#define MOVE_TO_PASSWD_AUTH do { \
if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { \
rc = SSH_OK; \
- state(data, SSH_AUTH_PASS_INIT); \
+ myssh_state(data, sshc, SSH_AUTH_PASS_INIT); \
} \
else { \
MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); \
@@ -543,7 +545,7 @@ cleanup:
#define MOVE_TO_KEY_AUTH do { \
if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { \
rc = SSH_OK; \
- state(data, SSH_AUTH_KEY_INIT); \
+ myssh_state(data, sshc, SSH_AUTH_KEY_INIT); \
} \
else { \
MOVE_TO_PASSWD_AUTH; \
@@ -553,7 +555,7 @@ cleanup:
#define MOVE_TO_GSSAPI_AUTH do { \
if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) { \
rc = SSH_OK; \
- state(data, SSH_AUTH_GSSAPI); \
+ myssh_state(data, sshc, SSH_AUTH_GSSAPI); \
} \
else { \
MOVE_TO_KEY_AUTH; \
@@ -561,10 +563,10 @@ cleanup:
} while(0)
static
-int myssh_auth_interactive(struct connectdata *conn)
+int myssh_auth_interactive(struct connectdata *conn,
+ struct ssh_conn *sshc)
{
int rc;
- struct ssh_conn *sshc = &conn->proto.sshc;
int nprompts;
restart:
@@ -625,178 +627,493 @@ restart:
return rc;
}
-/*
- * 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
- * to will be set to TRUE if the libssh function returns SSH_AGAIN
- * meaning it wants to be called again when the socket is ready
- */
-static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
+static void myssh_state_init(struct Curl_easy *data,
+ struct ssh_conn *sshc)
{
- CURLcode result = CURLE_OK;
- struct connectdata *conn = data->conn;
- struct SSHPROTO *protop = data->req.p.ssh;
- struct ssh_conn *sshc = &conn->proto.sshc;
- curl_socket_t sock = conn->sock[FIRSTSOCKET];
- int rc = SSH_NO_ERROR, err;
- int seekerr = CURL_SEEKFUNC_OK;
- const char *err_msg;
- *block = 0; /* we are not blocking by default */
-
- do {
-
- switch(sshc->state) {
- case SSH_INIT:
- sshc->secondCreateDirs = 0;
- sshc->nextstate = SSH_NO_STATE;
- sshc->actualcode = CURLE_OK;
+ sshc->secondCreateDirs = 0;
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_OK;
#if 0
- ssh_set_log_level(SSH_LOG_PROTOCOL);
+ ssh_set_log_level(SSH_LOG_PROTOCOL);
#endif
- /* Set libssh to non-blocking, since everything internally is
- non-blocking */
- ssh_set_blocking(sshc->ssh_session, 0);
+ /* Set libssh to non-blocking, since everything internally is
+ non-blocking */
+ ssh_set_blocking(sshc->ssh_session, 0);
- state(data, SSH_S_STARTUP);
- FALLTHROUGH();
+ myssh_state(data, sshc, SSH_S_STARTUP);
+}
- case SSH_S_STARTUP:
- rc = ssh_connect(sshc->ssh_session);
+static int myssh_state_startup(struct Curl_easy *data,
+ struct ssh_conn *sshc)
+{
+ struct connectdata *conn = data->conn;
+ int rc = ssh_connect(sshc->ssh_session);
- myssh_block2waitfor(conn, (rc == SSH_AGAIN));
- if(rc == SSH_AGAIN) {
- DEBUGF(infof(data, "ssh_connect -> EAGAIN"));
- break;
- }
+ myssh_block2waitfor(conn, sshc, (rc == SSH_AGAIN));
+ if(rc == SSH_AGAIN) {
+ DEBUGF(infof(data, "ssh_connect -> EAGAIN"));
+ }
+ else if(rc != SSH_OK) {
+ failf(data, "Failure establishing ssh session");
+ MOVE_TO_ERROR_STATE(CURLE_FAILED_INIT);
+ }
+ else
+ myssh_state(data, sshc, SSH_HOSTKEY);
- if(rc != SSH_OK) {
- failf(data, "Failure establishing ssh session");
- MOVE_TO_ERROR_STATE(CURLE_FAILED_INIT);
- break;
- }
+ return rc;
+}
- state(data, SSH_HOSTKEY);
+static int myssh_state_authlist(struct Curl_easy *data,
+ struct ssh_conn *sshc)
+{
+ int rc;
+ sshc->authed = FALSE;
- FALLTHROUGH();
- case SSH_HOSTKEY:
+ rc = ssh_userauth_none(sshc->ssh_session, NULL);
+ if(rc == SSH_AUTH_AGAIN)
+ return SSH_AGAIN;
+
+ if(rc == SSH_AUTH_SUCCESS) {
+ sshc->authed = TRUE;
+ infof(data, "Authenticated with none");
+ myssh_state(data, sshc, SSH_AUTH_DONE);
+ return rc;
+ }
+ else if(rc == SSH_AUTH_ERROR) {
+ MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
+ return rc;
+ }
+
+ sshc->auth_methods =
+ (unsigned int)ssh_userauth_list(sshc->ssh_session, NULL);
+ if(sshc->auth_methods)
+ infof(data, "SSH authentication methods available: %s%s%s%s",
+ sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY ?
+ "public key, ": "",
+ sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC ?
+ "GSSAPI, " : "",
+ sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE ?
+ "keyboard-interactive, " : "",
+ sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD ?
+ "password": "");
+ if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) {
+ myssh_state(data, sshc, SSH_AUTH_PKEY_INIT);
+ infof(data, "Authentication using SSH public key file");
+ }
+ else if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) {
+ myssh_state(data, sshc, SSH_AUTH_GSSAPI);
+ }
+ else if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {
+ myssh_state(data, sshc, SSH_AUTH_KEY_INIT);
+ }
+ else if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) {
+ myssh_state(data, sshc, SSH_AUTH_PASS_INIT);
+ }
+ else { /* unsupported authentication method */
+ MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
+ }
+ return rc;
+}
+
+static int myssh_state_auth_pkey_init(struct Curl_easy *data,
+ struct ssh_conn *sshc)
+{
+ int rc;
+ if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY)) {
+ MOVE_TO_GSSAPI_AUTH;
+ return 0;
+ }
+
+ /* Two choices, (1) private key was given on CMD,
+ * (2) use the "default" keys. */
+ if(data->set.str[STRING_SSH_PRIVATE_KEY]) {
+ if(sshc->pubkey && !data->set.ssl.key_passwd) {
+ rc = ssh_userauth_try_publickey(sshc->ssh_session, NULL,
+ sshc->pubkey);
+ if(rc == SSH_AUTH_AGAIN)
+ return SSH_AGAIN;
- rc = myssh_is_known(data);
if(rc != SSH_OK) {
- MOVE_TO_ERROR_STATE(CURLE_PEER_FAILED_VERIFICATION);
- break;
+ MOVE_TO_GSSAPI_AUTH;
+ return rc;
}
+ }
- state(data, SSH_AUTHLIST);
- FALLTHROUGH();
- case SSH_AUTHLIST:{
- sshc->authed = FALSE;
+ rc = ssh_pki_import_privkey_file(data->
+ set.str[STRING_SSH_PRIVATE_KEY],
+ data->set.ssl.key_passwd, NULL,
+ NULL, &sshc->privkey);
+ if(rc != SSH_OK) {
+ failf(data, "Could not load private key file %s",
+ data->set.str[STRING_SSH_PRIVATE_KEY]);
+ MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
+ return rc;
+ }
- rc = ssh_userauth_none(sshc->ssh_session, NULL);
- if(rc == SSH_AUTH_AGAIN) {
- rc = SSH_AGAIN;
- break;
- }
+ myssh_state(data, sshc, SSH_AUTH_PKEY);
+ }
+ else {
+ rc = ssh_userauth_publickey_auto(sshc->ssh_session, NULL,
+ data->set.ssl.key_passwd);
+ if(rc == SSH_AUTH_AGAIN)
+ return SSH_AGAIN;
+
+ if(rc == SSH_AUTH_SUCCESS) {
+ rc = SSH_OK;
+ sshc->authed = TRUE;
+ infof(data, "Completed public key authentication");
+ myssh_state(data, sshc, SSH_AUTH_DONE);
+ return rc;
+ }
- if(rc == SSH_AUTH_SUCCESS) {
- sshc->authed = TRUE;
- infof(data, "Authenticated with none");
- state(data, SSH_AUTH_DONE);
- break;
- }
- else if(rc == SSH_AUTH_ERROR) {
- MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
- break;
- }
+ MOVE_TO_GSSAPI_AUTH;
+ }
+ return rc;
+}
- sshc->auth_methods =
- (unsigned int)ssh_userauth_list(sshc->ssh_session, NULL);
- if(sshc->auth_methods)
- infof(data, "SSH authentication methods available: %s%s%s%s",
- sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY ?
- "public key, ": "",
- sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC ?
- "GSSAPI, " : "",
- sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE ?
- "keyboard-interactive, " : "",
- sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD ?
- "password": "");
- if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) {
- state(data, SSH_AUTH_PKEY_INIT);
- infof(data, "Authentication using SSH public key file");
- }
- else if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) {
- state(data, SSH_AUTH_GSSAPI);
- }
- else if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {
- state(data, SSH_AUTH_KEY_INIT);
- }
- else if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) {
- state(data, SSH_AUTH_PASS_INIT);
- }
- else { /* unsupported authentication method */
- MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
- break;
+static int myssh_state_upload_init(struct Curl_easy *data,
+ struct ssh_conn *sshc,
+ struct SSHPROTO *sshp)
+{
+ int flags;
+ int rc = 0;
+
+ if(data->state.resume_from) {
+ sftp_attributes attrs;
+
+ if(data->state.resume_from < 0) {
+ attrs = sftp_stat(sshc->sftp_session, sshp->path);
+ if(attrs) {
+ curl_off_t size = attrs->size;
+ if(size < 0) {
+ failf(data, "Bad file size (%" FMT_OFF_T ")", size);
+ MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME);
+ return rc;
}
+ data->state.resume_from = attrs->size;
- break;
+ sftp_attributes_free(attrs);
}
- case SSH_AUTH_PKEY_INIT:
- if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY)) {
- MOVE_TO_GSSAPI_AUTH;
- break;
+ else {
+ data->state.resume_from = 0;
}
+ }
+ }
- /* Two choices, (1) private key was given on CMD,
- * (2) use the "default" keys. */
- if(data->set.str[STRING_SSH_PRIVATE_KEY]) {
- if(sshc->pubkey && !data->set.ssl.key_passwd) {
- rc = ssh_userauth_try_publickey(sshc->ssh_session, NULL,
- sshc->pubkey);
- if(rc == SSH_AUTH_AGAIN) {
- rc = SSH_AGAIN;
- break;
- }
+ if(data->set.remote_append)
+ /* Try to open for append, but create if nonexisting */
+ flags = O_WRONLY|O_CREAT|O_APPEND;
+ else if(data->state.resume_from > 0)
+ /* If we have restart position then open for append */
+ flags = O_WRONLY|O_APPEND;
+ else
+ /* Clear file before writing (normal behavior) */
+ flags = O_WRONLY|O_CREAT|O_TRUNC;
+
+ if(sshc->sftp_file)
+ sftp_close(sshc->sftp_file);
+ sshc->sftp_file =
+ sftp_open(sshc->sftp_session, sshp->path,
+ flags, (mode_t)data->set.new_file_perms);
+ if(!sshc->sftp_file) {
+ int err = sftp_get_error(sshc->sftp_session);
+
+ if(((err == SSH_FX_NO_SUCH_FILE || err == SSH_FX_FAILURE ||
+ err == SSH_FX_NO_SUCH_PATH)) &&
+ (data->set.ftp_create_missing_dirs &&
+ (strlen(sshp->path) > 1))) {
+ /* try to create the path remotely */
+ rc = 0;
+ sshc->secondCreateDirs = 1;
+ myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS_INIT);
+ return rc;
+ }
+ else {
+ MOVE_TO_SFTP_CLOSE_STATE();
+ return rc;
+ }
+ }
- if(rc != SSH_OK) {
- MOVE_TO_GSSAPI_AUTH;
- break;
- }
- }
+ /* If we have a restart point then we need to seek to the correct
+ position. */
+ if(data->state.resume_from > 0) {
+ int seekerr = CURL_SEEKFUNC_OK;
+ /* Let's read off the proper amount of bytes from the input. */
+ if(data->set.seek_func) {
+ Curl_set_in_callback(data, TRUE);
+ seekerr = data->set.seek_func(data->set.seek_client,
+ data->state.resume_from, SEEK_SET);
+ Curl_set_in_callback(data, FALSE);
+ }
- rc = ssh_pki_import_privkey_file(data->
- set.str[STRING_SSH_PRIVATE_KEY],
- data->set.ssl.key_passwd, NULL,
- NULL, &sshc->privkey);
- if(rc != SSH_OK) {
- failf(data, "Could not load private key file %s",
- data->set.str[STRING_SSH_PRIVATE_KEY]);
- MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
- break;
+ if(seekerr != CURL_SEEKFUNC_OK) {
+ curl_off_t passed = 0;
+
+ if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
+ failf(data, "Could not seek stream");
+ MOVE_TO_ERROR_STATE(CURLE_FTP_COULDNT_USE_REST);
+ return rc;
+ }
+ /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
+ do {
+ char scratch[4*1024];
+ size_t readthisamountnow =
+ (data->state.resume_from - passed >
+ (curl_off_t)sizeof(scratch)) ?
+ sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);
+
+ size_t actuallyread =
+ data->state.fread_func(scratch, 1,
+ readthisamountnow, data->state.in);
+
+ passed += actuallyread;
+ if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
+ /* this checks for greater-than only to make sure that the
+ CURL_READFUNC_ABORT return code still aborts */
+ failf(data, "Failed to read data");
+ MOVE_TO_ERROR_STATE(CURLE_FTP_COULDNT_USE_REST);
+ return rc;
}
+ } while(passed < data->state.resume_from);
+ }
- state(data, SSH_AUTH_PKEY);
- break;
+ /* now, decrease the size of the read */
+ if(data->state.infilesize > 0) {
+ data->state.infilesize -= data->state.resume_from;
+ data->req.size = data->state.infilesize;
+ Curl_pgrsSetUploadSize(data, data->state.infilesize);
+ }
+
+ rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
+ if(rc) {
+ MOVE_TO_SFTP_CLOSE_STATE();
+ return rc;
+ }
+ }
+ if(data->state.infilesize > 0) {
+ data->req.size = data->state.infilesize;
+ Curl_pgrsSetUploadSize(data, data->state.infilesize);
+ }
+ /* upload data */
+ Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
+
+ /* not set by Curl_xfer_setup to preserve keepon bits */
+ data->conn->sockfd = data->conn->writesockfd;
+
+ /* store this original bitmask setup to use later on if we cannot
+ figure out a "real" bitmask */
+ sshc->orig_waitfor = data->req.keepon;
+
+ /* we want to use the _sending_ function even when the socket turns
+ out readable as the underlying libssh sftp send function will deal
+ with both accordingly */
+ data->state.select_bits = CURL_CSELECT_OUT;
+
+ /* since we do not really wait for anything at this point, we want the
+ state machine to move on as soon as possible so we set a very short
+ timeout here */
+ Curl_expire(data, 0, EXPIRE_RUN_NOW);
+#if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0)
+ sshc->sftp_send_state = 0;
+#endif
+ myssh_state(data, sshc, SSH_STOP);
+ return rc;
+}
+static int myssh_state_sftp_dowload_stat(struct Curl_easy *data,
+ struct ssh_conn *sshc)
+{
+ curl_off_t size;
+ int rc = 0;
+ sftp_attributes attrs = sftp_fstat(sshc->sftp_file);
+ if(!attrs ||
+ !(attrs->flags & SSH_FILEXFER_ATTR_SIZE) ||
+ (attrs->size == 0)) {
+ /*
+ * sftp_fstat did not return an error, so maybe the server
+ * just does not support stat()
+ * OR the server does not return a file size with a stat()
+ * OR file size is 0
+ */
+ data->req.size = -1;
+ data->req.maxdownload = -1;
+ Curl_pgrsSetDownloadSize(data, -1);
+ size = 0;
+ if(attrs)
+ sftp_attributes_free(attrs);
+ }
+ else {
+ size = attrs->size;
+
+ sftp_attributes_free(attrs);
+
+ if(size < 0) {
+ failf(data, "Bad file size (%" FMT_OFF_T ")", size);
+ MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME);
+ return rc;
+ }
+ if(data->state.use_range) {
+ curl_off_t from, to;
+ const char *p = data->state.range;
+ int from_t, to_t;
+
+ from_t = curlx_str_number(&p, &from, CURL_OFF_T_MAX);
+ if(from_t == STRE_OVERFLOW) {
+ MOVE_TO_ERROR_STATE(CURLE_RANGE_ERROR);
+ return rc;
+ }
+ curlx_str_passblanks(&p);
+ (void)curlx_str_single(&p, '-');
+
+ to_t = curlx_str_numblanks(&p, &to);
+ if(to_t == STRE_OVERFLOW)
+ return CURLE_RANGE_ERROR;
+
+ if((to_t == STRE_NO_NUM) || (to >= size)) {
+ to = size - 1;
+ to_t = STRE_OK;
+ }
+
+ if(from_t == STRE_NO_NUM) {
+ /* from is relative to end of file */
+ from = size - to;
+ to = size - 1;
+ from_t = STRE_OK;
+ }
+ if(from > size) {
+ failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
+ FMT_OFF_T ")", from, size);
+ MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME);
+ return rc;
+ }
+ if(from > to) {
+ from = to;
+ size = 0;
}
else {
- rc = ssh_userauth_publickey_auto(sshc->ssh_session, NULL,
- data->set.ssl.key_passwd);
- if(rc == SSH_AUTH_AGAIN) {
- rc = SSH_AGAIN;
- break;
- }
- if(rc == SSH_AUTH_SUCCESS) {
- rc = SSH_OK;
- sshc->authed = TRUE;
- infof(data, "Completed public key authentication");
- state(data, SSH_AUTH_DONE);
- break;
+ if((to - from) == CURL_OFF_T_MAX) {
+ MOVE_TO_ERROR_STATE(CURLE_RANGE_ERROR);
+ return rc;
}
+ size = to - from + 1;
+ }
- MOVE_TO_GSSAPI_AUTH;
+ rc = sftp_seek64(sshc->sftp_file, from);
+ if(rc) {
+ MOVE_TO_SFTP_CLOSE_STATE();
+ return rc;
}
+ }
+ data->req.size = size;
+ data->req.maxdownload = size;
+ Curl_pgrsSetDownloadSize(data, size);
+ }
+
+ /* We can resume if we can seek to the resume position */
+ if(data->state.resume_from) {
+ if(data->state.resume_from < 0) {
+ /* We are supposed to download the last abs(from) bytes */
+ if((curl_off_t)size < -data->state.resume_from) {
+ failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
+ FMT_OFF_T ")", data->state.resume_from, size);
+ MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME);
+ return rc;
+ }
+ /* download from where? */
+ data->state.resume_from += size;
+ }
+ else {
+ if((curl_off_t)size < data->state.resume_from) {
+ failf(data, "Offset (%" FMT_OFF_T
+ ") was beyond file size (%" FMT_OFF_T ")",
+ data->state.resume_from, size);
+ MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME);
+ return rc;
+ }
+ }
+ /* Now store the number of bytes we are expected to download */
+ data->req.size = size - data->state.resume_from;
+ data->req.maxdownload = size - data->state.resume_from;
+ Curl_pgrsSetDownloadSize(data,
+ size - data->state.resume_from);
+
+ rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
+ if(rc) {
+ MOVE_TO_SFTP_CLOSE_STATE();
+ return rc;
+ }
+ }
+
+ /* Setup the actual download */
+ if(data->req.size == 0) {
+ /* no data to transfer */
+ Curl_xfer_setup_nop(data);
+ infof(data, "File already completely downloaded");
+ myssh_state(data, sshc, SSH_STOP);
+ return rc;
+ }
+ Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE);
+
+ /* not set by Curl_xfer_setup to preserve keepon bits */
+ data->conn->writesockfd = data->conn->sockfd;
+
+ /* we want to use the _receiving_ function even when the socket turns
+ out writableable as the underlying libssh recv function will deal
+ with both accordingly */
+ data->state.select_bits = CURL_CSELECT_IN;
+
+ sshc->sftp_recv_state = 0;
+ myssh_state(data, sshc, SSH_STOP);
+
+ return rc;
+}
+
+/*
+ * 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
+ * to will be set to TRUE if the libssh function returns SSH_AGAIN
+ * meaning it wants to be called again when the socket is ready
+ */
+static CURLcode myssh_statemach_act(struct Curl_easy *data,
+ struct ssh_conn *sshc,
+ struct SSHPROTO *sshp,
+ bool *block)
+{
+ CURLcode result = CURLE_OK;
+ struct connectdata *conn = data->conn;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
+ int rc = SSH_NO_ERROR, err;
+ const char *err_msg;
+ *block = 0; /* we are not blocking by default */
+
+ do {
+
+ switch(sshc->state) {
+ case SSH_INIT:
+ myssh_state_init(data, sshc);
+ FALLTHROUGH();
+
+ case SSH_S_STARTUP:
+ rc = myssh_state_startup(data, sshc);
+ if(rc)
+ break;
+ FALLTHROUGH();
+ case SSH_HOSTKEY:
+ rc = myssh_is_known(data, sshc);
+ if(rc != SSH_OK) {
+ MOVE_TO_ERROR_STATE(CURLE_PEER_FAILED_VERIFICATION);
+ break;
+ }
+
+ myssh_state(data, sshc, SSH_AUTHLIST);
+ FALLTHROUGH();
+ case SSH_AUTHLIST:
+ rc = myssh_state_authlist(data, sshc);
+ break;
+ case SSH_AUTH_PKEY_INIT:
+ rc = myssh_state_auth_pkey_init(data, sshc);
break;
case SSH_AUTH_PKEY:
rc = ssh_userauth_publickey(sshc->ssh_session, NULL, sshc->privkey);
@@ -808,7 +1125,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
if(rc == SSH_AUTH_SUCCESS) {
sshc->authed = TRUE;
infof(data, "Completed public key authentication");
- state(data, SSH_AUTH_DONE);
+ myssh_state(data, sshc, SSH_AUTH_DONE);
break;
}
else {
@@ -833,7 +1150,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
rc = SSH_OK;
sshc->authed = TRUE;
infof(data, "Completed gssapi authentication");
- state(data, SSH_AUTH_DONE);
+ myssh_state(data, sshc, SSH_AUTH_DONE);
break;
}
@@ -842,7 +1159,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
case SSH_AUTH_KEY_INIT:
if(data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) {
- state(data, SSH_AUTH_KEY);
+ myssh_state(data, sshc, SSH_AUTH_KEY);
}
else {
MOVE_TO_PASSWD_AUTH;
@@ -851,14 +1168,14 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
case SSH_AUTH_KEY:
/* keyboard-interactive authentication */
- rc = myssh_auth_interactive(conn);
+ rc = myssh_auth_interactive(conn, sshc);
if(rc == SSH_AGAIN) {
break;
}
if(rc == SSH_OK) {
sshc->authed = TRUE;
infof(data, "completed keyboard interactive authentication");
- state(data, SSH_AUTH_DONE);
+ myssh_state(data, sshc, SSH_AUTH_DONE);
}
else {
MOVE_TO_PASSWD_AUTH;
@@ -870,7 +1187,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
break;
}
- state(data, SSH_AUTH_PASS);
+ myssh_state(data, sshc, SSH_AUTH_PASS);
FALLTHROUGH();
case SSH_AUTH_PASS:
@@ -883,7 +1200,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
if(rc == SSH_AUTH_SUCCESS) {
sshc->authed = TRUE;
infof(data, "Completed password authentication");
- state(data, SSH_AUTH_DONE);
+ myssh_state(data, sshc, SSH_AUTH_DONE);
}
else {
MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
@@ -908,11 +1225,11 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
conn->writesockfd = CURL_SOCKET_BAD;
if(conn->handler->protocol == CURLPROTO_SFTP) {
- state(data, SSH_SFTP_INIT);
+ myssh_state(data, sshc, SSH_SFTP_INIT);
break;
}
infof(data, "SSH CONNECT phase done");
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
case SSH_SFTP_INIT:
@@ -933,7 +1250,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
MOVE_TO_ERROR_STATE(sftp_error_to_CURLE(SSH_FX_FAILURE));
break;
}
- state(data, SSH_SFTP_REALPATH);
+ myssh_state(data, sshc, SSH_SFTP_REALPATH);
FALLTHROUGH();
case SSH_SFTP_REALPATH:
/*
@@ -954,24 +1271,24 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
since the homedir will remain the same between request but the
working path will not. */
DEBUGF(infof(data, "SSH CONNECT phase done"));
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
case SSH_SFTP_QUOTE_INIT:
- result = Curl_getworkingpath(data, sshc->homedir, &protop->path);
+ result = Curl_getworkingpath(data, sshc->homedir, &sshp->path);
if(result) {
sshc->actualcode = result;
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
}
if(data->set.quote) {
infof(data, "Sending quote commands");
sshc->quote_item = data->set.quote;
- state(data, SSH_SFTP_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE);
}
else {
- state(data, SSH_SFTP_GETINFO);
+ myssh_state(data, sshc, SSH_SFTP_GETINFO);
}
break;
@@ -979,16 +1296,16 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
if(data->set.postquote) {
infof(data, "Sending quote commands");
sshc->quote_item = data->set.postquote;
- state(data, SSH_SFTP_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE);
}
else {
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
}
break;
case SSH_SFTP_QUOTE:
/* Send any quote commands */
- sftp_quote(data);
+ sftp_quote(data, sshc, sshp);
break;
case SSH_SFTP_NEXT_QUOTE:
@@ -998,21 +1315,21 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
sshc->quote_item = sshc->quote_item->next;
if(sshc->quote_item) {
- state(data, SSH_SFTP_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE);
}
else {
if(sshc->nextstate != SSH_NO_STATE) {
- state(data, sshc->nextstate);
+ myssh_state(data, sshc, sshc->nextstate);
sshc->nextstate = SSH_NO_STATE;
}
else {
- state(data, SSH_SFTP_GETINFO);
+ myssh_state(data, sshc, SSH_SFTP_GETINFO);
}
}
break;
case SSH_SFTP_QUOTE_STAT:
- sftp_quote_stat(data);
+ sftp_quote_stat(data, sshc);
break;
case SSH_SFTP_QUOTE_SETSTAT:
@@ -1023,7 +1340,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_safefree(sshc->quote_path2);
failf(data, "Attempt to set SFTP stats failed: %s",
ssh_get_error(sshc->ssh_session));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
/* sshc->actualcode = sftp_error_to_CURLE(err);
@@ -1031,7 +1348,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
* the error the libssh2 backend is returning */
break;
}
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
break;
case SSH_SFTP_QUOTE_SYMLINK:
@@ -1042,12 +1359,12 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_safefree(sshc->quote_path2);
failf(data, "symlink command failed: %s",
ssh_get_error(sshc->ssh_session));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
break;
case SSH_SFTP_QUOTE_MKDIR:
@@ -1057,12 +1374,12 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_safefree(sshc->quote_path1);
failf(data, "mkdir command failed: %s",
ssh_get_error(sshc->ssh_session));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
break;
case SSH_SFTP_QUOTE_RENAME:
@@ -1073,12 +1390,12 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_safefree(sshc->quote_path2);
failf(data, "rename command failed: %s",
ssh_get_error(sshc->ssh_session));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
break;
case SSH_SFTP_QUOTE_RMDIR:
@@ -1087,12 +1404,12 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_safefree(sshc->quote_path1);
failf(data, "rmdir command failed: %s",
ssh_get_error(sshc->ssh_session));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
break;
case SSH_SFTP_QUOTE_UNLINK:
@@ -1101,12 +1418,12 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_safefree(sshc->quote_path1);
failf(data, "rm command failed: %s",
ssh_get_error(sshc->ssh_session));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
break;
case SSH_SFTP_QUOTE_STATVFS:
@@ -1118,7 +1435,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_safefree(sshc->quote_path1);
failf(data, "statvfs command failed: %s",
ssh_get_error(sshc->ssh_session));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
@@ -1151,7 +1468,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
if(!tmp) {
result = CURLE_OUT_OF_MEMORY;
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
break;
}
@@ -1159,21 +1476,21 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
free(tmp);
if(result) {
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = result;
}
}
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
break;
}
case SSH_SFTP_GETINFO:
if(data->set.get_filetime) {
- state(data, SSH_SFTP_FILETIME);
+ myssh_state(data, sshc, SSH_SFTP_FILETIME);
}
else {
- state(data, SSH_SFTP_TRANS_INIT);
+ myssh_state(data, sshc, SSH_SFTP_TRANS_INIT);
}
break;
@@ -1181,180 +1498,38 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
{
sftp_attributes attrs;
- attrs = sftp_stat(sshc->sftp_session, protop->path);
+ attrs = sftp_stat(sshc->sftp_session, sshp->path);
if(attrs) {
data->info.filetime = attrs->mtime;
sftp_attributes_free(attrs);
}
- state(data, SSH_SFTP_TRANS_INIT);
+ myssh_state(data, sshc, SSH_SFTP_TRANS_INIT);
break;
}
case SSH_SFTP_TRANS_INIT:
if(data->state.upload)
- state(data, SSH_SFTP_UPLOAD_INIT);
+ myssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT);
else {
- if(protop->path[strlen(protop->path)-1] == '/')
- state(data, SSH_SFTP_READDIR_INIT);
+ if(sshp->path[strlen(sshp->path)-1] == '/')
+ myssh_state(data, sshc, SSH_SFTP_READDIR_INIT);
else
- state(data, SSH_SFTP_DOWNLOAD_INIT);
+ myssh_state(data, sshc, SSH_SFTP_DOWNLOAD_INIT);
}
break;
case SSH_SFTP_UPLOAD_INIT:
- {
- int flags;
-
- if(data->state.resume_from) {
- sftp_attributes attrs;
-
- if(data->state.resume_from < 0) {
- attrs = sftp_stat(sshc->sftp_session, protop->path);
- if(attrs) {
- curl_off_t size = attrs->size;
- if(size < 0) {
- failf(data, "Bad file size (%" FMT_OFF_T ")", size);
- MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME);
- break;
- }
- data->state.resume_from = attrs->size;
-
- sftp_attributes_free(attrs);
- }
- else {
- data->state.resume_from = 0;
- }
- }
- }
-
- if(data->set.remote_append)
- /* Try to open for append, but create if nonexisting */
- flags = O_WRONLY|O_CREAT|O_APPEND;
- else if(data->state.resume_from > 0)
- /* If we have restart position then open for append */
- flags = O_WRONLY|O_APPEND;
- else
- /* Clear file before writing (normal behavior) */
- flags = O_WRONLY|O_CREAT|O_TRUNC;
-
- if(sshc->sftp_file)
- sftp_close(sshc->sftp_file);
- sshc->sftp_file =
- sftp_open(sshc->sftp_session, protop->path,
- flags, (mode_t)data->set.new_file_perms);
- if(!sshc->sftp_file) {
- err = sftp_get_error(sshc->sftp_session);
-
- if(((err == SSH_FX_NO_SUCH_FILE || err == SSH_FX_FAILURE ||
- err == SSH_FX_NO_SUCH_PATH)) &&
- (data->set.ftp_create_missing_dirs &&
- (strlen(protop->path) > 1))) {
- /* try to create the path remotely */
- rc = 0;
- sshc->secondCreateDirs = 1;
- state(data, SSH_SFTP_CREATE_DIRS_INIT);
- break;
- }
- else {
- MOVE_TO_SFTP_CLOSE_STATE();
- break;
- }
- }
-
- /* If we have a restart point then we need to seek to the correct
- position. */
- if(data->state.resume_from > 0) {
- /* Let's read off the proper amount of bytes from the input. */
- if(data->set.seek_func) {
- Curl_set_in_callback(data, TRUE);
- seekerr = data->set.seek_func(data->set.seek_client,
- data->state.resume_from, SEEK_SET);
- Curl_set_in_callback(data, FALSE);
- }
-
- if(seekerr != CURL_SEEKFUNC_OK) {
- curl_off_t passed = 0;
-
- if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
- failf(data, "Could not seek stream");
- return CURLE_FTP_COULDNT_USE_REST;
- }
- /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
- do {
- char scratch[4*1024];
- size_t readthisamountnow =
- (data->state.resume_from - passed >
- (curl_off_t)sizeof(scratch)) ?
- sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);
-
- size_t actuallyread =
- data->state.fread_func(scratch, 1,
- readthisamountnow, data->state.in);
-
- passed += actuallyread;
- if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
- /* this checks for greater-than only to make sure that the
- CURL_READFUNC_ABORT return code still aborts */
- failf(data, "Failed to read data");
- MOVE_TO_ERROR_STATE(CURLE_FTP_COULDNT_USE_REST);
- break;
- }
- } while(passed < data->state.resume_from);
- if(rc)
- break;
- }
-
- /* now, decrease the size of the read */
- if(data->state.infilesize > 0) {
- data->state.infilesize -= data->state.resume_from;
- data->req.size = data->state.infilesize;
- Curl_pgrsSetUploadSize(data, data->state.infilesize);
- }
-
- rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
- if(rc) {
- MOVE_TO_SFTP_CLOSE_STATE();
- break;
- }
- }
- if(data->state.infilesize > 0) {
- data->req.size = data->state.infilesize;
- Curl_pgrsSetUploadSize(data, data->state.infilesize);
- }
- /* upload data */
- Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
-
- /* not set by Curl_xfer_setup to preserve keepon bits */
- conn->sockfd = conn->writesockfd;
-
- /* store this original bitmask setup to use later on if we cannot
- figure out a "real" bitmask */
- sshc->orig_waitfor = data->req.keepon;
-
- /* we want to use the _sending_ function even when the socket turns
- out readable as the underlying libssh sftp send function will deal
- with both accordingly */
- data->state.select_bits = CURL_CSELECT_OUT;
-
- /* since we do not really wait for anything at this point, we want the
- state machine to move on as soon as possible so we set a very short
- timeout here */
- Curl_expire(data, 0, EXPIRE_RUN_NOW);
-#if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0)
- sshc->sftp_send_state = 0;
-#endif
- state(data, SSH_STOP);
+ rc = myssh_state_upload_init(data, sshc, sshp);
break;
- }
case SSH_SFTP_CREATE_DIRS_INIT:
- if(strlen(protop->path) > 1) {
- sshc->slash_pos = protop->path + 1; /* ignore the leading '/' */
- state(data, SSH_SFTP_CREATE_DIRS);
+ if(strlen(sshp->path) > 1) {
+ sshc->slash_pos = sshp->path + 1; /* ignore the leading '/' */
+ myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS);
}
else {
- state(data, SSH_SFTP_UPLOAD_INIT);
+ myssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT);
}
break;
@@ -1363,16 +1538,16 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
if(sshc->slash_pos) {
*sshc->slash_pos = 0;
- infof(data, "Creating directory '%s'", protop->path);
- state(data, SSH_SFTP_CREATE_DIRS_MKDIR);
+ infof(data, "Creating directory '%s'", sshp->path);
+ myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS_MKDIR);
break;
}
- state(data, SSH_SFTP_UPLOAD_INIT);
+ myssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT);
break;
case SSH_SFTP_CREATE_DIRS_MKDIR:
/* 'mode' - parameter is preliminary - default to 0644 */
- rc = sftp_mkdir(sshc->sftp_session, protop->path,
+ rc = sftp_mkdir(sshc->sftp_session, sshp->path,
(mode_t)data->set.new_directory_perms);
*sshc->slash_pos = '/';
++sshc->slash_pos;
@@ -1391,13 +1566,13 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
}
rc = 0; /* clear rc and continue */
}
- state(data, SSH_SFTP_CREATE_DIRS);
+ myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS);
break;
case SSH_SFTP_READDIR_INIT:
Curl_pgrsSetDownloadSize(data, -1);
if(data->req.no_body) {
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
}
@@ -1406,18 +1581,18 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
* listing
*/
sshc->sftp_dir = sftp_opendir(sshc->sftp_session,
- protop->path);
+ sshp->path);
if(!sshc->sftp_dir) {
failf(data, "Could not open directory for reading: %s",
ssh_get_error(sshc->ssh_session));
MOVE_TO_SFTP_CLOSE_STATE();
break;
}
- state(data, SSH_SFTP_READDIR);
+ myssh_state(data, sshc, SSH_SFTP_READDIR);
break;
case SSH_SFTP_READDIR:
- Curl_dyn_reset(&sshc->readdir_buf);
+ curlx_dyn_reset(&sshc->readdir_buf);
if(sshc->readdir_attrs)
sftp_attributes_free(sshc->readdir_attrs);
@@ -1432,7 +1607,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
tmpLine = aprintf("%s\n", sshc->readdir_filename);
if(!tmpLine) {
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->actualcode = CURLE_OUT_OF_MEMORY;
break;
}
@@ -1441,39 +1616,39 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
free(tmpLine);
if(result) {
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
}
}
else {
- if(Curl_dyn_add(&sshc->readdir_buf, sshc->readdir_longentry)) {
+ if(curlx_dyn_add(&sshc->readdir_buf, sshc->readdir_longentry)) {
sshc->actualcode = CURLE_OUT_OF_MEMORY;
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
}
if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
((sshc->readdir_attrs->permissions & SSH_S_IFMT) ==
SSH_S_IFLNK)) {
- sshc->readdir_linkPath = aprintf("%s%s", protop->path,
+ sshc->readdir_linkPath = aprintf("%s%s", sshp->path,
sshc->readdir_filename);
if(!sshc->readdir_linkPath) {
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->actualcode = CURLE_OUT_OF_MEMORY;
break;
}
- state(data, SSH_SFTP_READDIR_LINK);
+ myssh_state(data, sshc, SSH_SFTP_READDIR_LINK);
break;
}
- state(data, SSH_SFTP_READDIR_BOTTOM);
+ myssh_state(data, sshc, SSH_SFTP_READDIR_BOTTOM);
break;
}
}
else if(sftp_dir_eof(sshc->sftp_dir)) {
- state(data, SSH_SFTP_READDIR_DONE);
+ myssh_state(data, sshc, SSH_SFTP_READDIR_DONE);
break;
}
else {
@@ -1515,8 +1690,8 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_safefree(sshc->readdir_linkPath);
- if(Curl_dyn_addf(&sshc->readdir_buf, " -> %s",
- sshc->readdir_filename)) {
+ if(curlx_dyn_addf(&sshc->readdir_buf, " -> %s",
+ sshc->readdir_filename)) {
sshc->actualcode = CURLE_OUT_OF_MEMORY;
break;
}
@@ -1526,24 +1701,24 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
sshc->readdir_filename = NULL;
sshc->readdir_longentry = NULL;
- state(data, SSH_SFTP_READDIR_BOTTOM);
+ myssh_state(data, sshc, SSH_SFTP_READDIR_BOTTOM);
FALLTHROUGH();
case SSH_SFTP_READDIR_BOTTOM:
- if(Curl_dyn_addn(&sshc->readdir_buf, "\n", 1))
+ if(curlx_dyn_addn(&sshc->readdir_buf, "\n", 1))
result = CURLE_OUT_OF_MEMORY;
else
result = Curl_client_write(data, CLIENTWRITE_BODY,
- Curl_dyn_ptr(&sshc->readdir_buf),
- Curl_dyn_len(&sshc->readdir_buf));
+ curlx_dyn_ptr(&sshc->readdir_buf),
+ curlx_dyn_len(&sshc->readdir_buf));
ssh_string_free_char(sshc->readdir_tmp);
sshc->readdir_tmp = NULL;
if(result) {
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
}
else
- state(data, SSH_SFTP_READDIR);
+ myssh_state(data, sshc, SSH_SFTP_READDIR);
break;
case SSH_SFTP_READDIR_DONE:
@@ -1552,7 +1727,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
/* no data to transfer */
Curl_xfer_setup_nop(data);
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
case SSH_SFTP_DOWNLOAD_INIT:
@@ -1562,7 +1737,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
if(sshc->sftp_file)
sftp_close(sshc->sftp_file);
- sshc->sftp_file = sftp_open(sshc->sftp_session, protop->path,
+ sshc->sftp_file = sftp_open(sshc->sftp_session, sshp->path,
O_RDONLY, (mode_t)data->set.new_file_perms);
if(!sshc->sftp_file) {
failf(data, "Could not open remote file for reading: %s",
@@ -1572,160 +1747,19 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
break;
}
sftp_file_set_nonblocking(sshc->sftp_file);
- state(data, SSH_SFTP_DOWNLOAD_STAT);
+ myssh_state(data, sshc, SSH_SFTP_DOWNLOAD_STAT);
break;
case SSH_SFTP_DOWNLOAD_STAT:
- {
- sftp_attributes attrs;
- curl_off_t size;
-
- attrs = sftp_fstat(sshc->sftp_file);
- if(!attrs ||
- !(attrs->flags & SSH_FILEXFER_ATTR_SIZE) ||
- (attrs->size == 0)) {
- /*
- * sftp_fstat did not return an error, so maybe the server
- * just does not support stat()
- * OR the server does not return a file size with a stat()
- * OR file size is 0
- */
- data->req.size = -1;
- data->req.maxdownload = -1;
- Curl_pgrsSetDownloadSize(data, -1);
- size = 0;
- }
- else {
- size = attrs->size;
-
- sftp_attributes_free(attrs);
-
- if(size < 0) {
- failf(data, "Bad file size (%" FMT_OFF_T ")", size);
- return CURLE_BAD_DOWNLOAD_RESUME;
- }
- if(data->state.use_range) {
- curl_off_t from, to;
- const char *p = data->state.range;
- int from_t, to_t;
-
- from_t = Curl_str_number(&p, &from, CURL_OFF_T_MAX);
- if(from_t == STRE_OVERFLOW)
- return CURLE_RANGE_ERROR;
- Curl_str_passblanks(&p);
- (void)Curl_str_single(&p, '-');
-
- to_t = Curl_str_numblanks(&p, &to);
- if(to_t == STRE_OVERFLOW)
- return CURLE_RANGE_ERROR;
-
- if((to_t == STRE_NO_NUM) || (to >= size)) {
- to = size - 1;
- to_t = STRE_OK;
- }
-
- if(from_t == STRE_NO_NUM) {
- /* from is relative to end of file */
- from = size - to;
- to = size - 1;
- from_t = STRE_OK;
- }
- if(from > size) {
- failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
- FMT_OFF_T ")", from, size);
- return CURLE_BAD_DOWNLOAD_RESUME;
- }
- if(from > to) {
- from = to;
- size = 0;
- }
- else {
- if((to - from) == CURL_OFF_T_MAX)
- return CURLE_RANGE_ERROR;
- size = to - from + 1;
- }
-
- rc = sftp_seek64(sshc->sftp_file, from);
- if(rc) {
- MOVE_TO_SFTP_CLOSE_STATE();
- break;
- }
- }
- data->req.size = size;
- data->req.maxdownload = size;
- Curl_pgrsSetDownloadSize(data, size);
- }
-
- /* We can resume if we can seek to the resume position */
- if(data->state.resume_from) {
- if(data->state.resume_from < 0) {
- /* We are supposed to download the last abs(from) bytes */
- if((curl_off_t)size < -data->state.resume_from) {
- failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
- FMT_OFF_T ")", data->state.resume_from, size);
- return CURLE_BAD_DOWNLOAD_RESUME;
- }
- /* download from where? */
- data->state.resume_from += size;
- }
- else {
- if((curl_off_t)size < data->state.resume_from) {
- failf(data, "Offset (%" FMT_OFF_T
- ") was beyond file size (%" FMT_OFF_T ")",
- data->state.resume_from, size);
- return CURLE_BAD_DOWNLOAD_RESUME;
- }
- }
- /* Now store the number of bytes we are expected to download */
- data->req.size = size - data->state.resume_from;
- data->req.maxdownload = size - data->state.resume_from;
- Curl_pgrsSetDownloadSize(data,
- size - data->state.resume_from);
-
- rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
- if(rc) {
- MOVE_TO_SFTP_CLOSE_STATE();
- break;
- }
- }
- }
-
- /* Setup the actual download */
- if(data->req.size == 0) {
- /* no data to transfer */
- Curl_xfer_setup_nop(data);
- infof(data, "File already completely downloaded");
- state(data, SSH_STOP);
+ rc = myssh_state_sftp_dowload_stat(data, sshc);
break;
- }
- Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE);
-
- /* not set by Curl_xfer_setup to preserve keepon bits */
- conn->writesockfd = conn->sockfd;
-
- /* we want to use the _receiving_ function even when the socket turns
- out writableable as the underlying libssh recv function will deal
- with both accordingly */
- data->state.select_bits = CURL_CSELECT_IN;
-
- if(result) {
- /* this should never occur; the close state should be entered
- at the time the error occurs */
- state(data, SSH_SFTP_CLOSE);
- sshc->actualcode = result;
- }
- else {
- sshc->sftp_recv_state = 0;
- state(data, SSH_STOP);
- }
- break;
case SSH_SFTP_CLOSE:
if(sshc->sftp_file) {
sftp_close(sshc->sftp_file);
sshc->sftp_file = NULL;
}
- Curl_safefree(protop->path);
+ Curl_safefree(sshp->path);
DEBUGF(infof(data, "SFTP DONE done"));
@@ -1734,11 +1768,11 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
SSH_SFTP_CLOSE to pass the correct result back */
if(sshc->nextstate != SSH_NO_STATE &&
sshc->nextstate != SSH_SFTP_CLOSE) {
- state(data, sshc->nextstate);
+ myssh_state(data, sshc, sshc->nextstate);
sshc->nextstate = SSH_SFTP_CLOSE;
}
else {
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
result = sshc->actualcode;
}
break;
@@ -1767,14 +1801,14 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
SSH_STRING_FREE_CHAR(sshc->homedir);
- state(data, SSH_SESSION_DISCONNECT);
+ myssh_state(data, sshc, SSH_SESSION_DISCONNECT);
break;
case SSH_SCP_TRANS_INIT:
- result = Curl_getworkingpath(data, sshc->homedir, &protop->path);
+ result = Curl_getworkingpath(data, sshc->homedir, &sshp->path);
if(result) {
sshc->actualcode = result;
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
}
@@ -1790,13 +1824,13 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
}
sshc->scp_session =
- ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, protop->path);
- state(data, SSH_SCP_UPLOAD_INIT);
+ ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, sshp->path);
+ myssh_state(data, sshc, SSH_SCP_UPLOAD_INIT);
}
else {
sshc->scp_session =
- ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, protop->path);
- state(data, SSH_SCP_DOWNLOAD_INIT);
+ ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, sshp->path);
+ myssh_state(data, sshc, SSH_SCP_DOWNLOAD_INIT);
}
if(!sshc->scp_session) {
@@ -1817,7 +1851,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
break;
}
- rc = ssh_scp_push_file64(sshc->scp_session, protop->path,
+ rc = ssh_scp_push_file64(sshc->scp_session, sshp->path,
(uint64_t)data->state.infilesize,
(int)data->set.new_file_perms);
@@ -1843,7 +1877,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
with both accordingly */
data->state.select_bits = CURL_CSELECT_OUT;
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
@@ -1856,7 +1890,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
break;
}
- state(data, SSH_SCP_DOWNLOAD);
+ myssh_state(data, sshc, SSH_SCP_DOWNLOAD);
FALLTHROUGH();
case SSH_SCP_DOWNLOAD:{
@@ -1883,14 +1917,14 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
with both accordingly */
data->state.select_bits = CURL_CSELECT_IN;
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
}
case SSH_SCP_DONE:
if(data->state.upload)
- state(data, SSH_SCP_SEND_EOF);
+ myssh_state(data, sshc, SSH_SCP_SEND_EOF);
else
- state(data, SSH_SCP_CHANNEL_FREE);
+ myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE);
break;
case SSH_SCP_SEND_EOF:
@@ -1908,7 +1942,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
}
}
- state(data, SSH_SCP_CHANNEL_FREE);
+ myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE);
break;
case SSH_SCP_CHANNEL_FREE:
@@ -1920,7 +1954,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
ssh_set_blocking(sshc->ssh_session, 0);
- state(data, SSH_SESSION_DISCONNECT);
+ myssh_state(data, sshc, SSH_SESSION_DISCONNECT);
FALLTHROUGH();
case SSH_SESSION_DISCONNECT:
@@ -1932,6 +1966,15 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
sshc->scp_session = NULL;
}
+ 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;
+ }
+
ssh_disconnect(sshc->ssh_session);
if(!ssh_version(SSH_VERSION_INT(0, 10, 0))) {
/* conn->sock[FIRSTSOCKET] is closed by ssh_disconnect behind our back,
@@ -1942,24 +1985,24 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
SSH_STRING_FREE_CHAR(sshc->homedir);
- state(data, SSH_SESSION_FREE);
+ myssh_state(data, sshc, SSH_SESSION_FREE);
FALLTHROUGH();
case SSH_SESSION_FREE:
- sshc_cleanup(sshc, data);
+ sshc_cleanup(sshc);
/* the code we are about to return */
result = sshc->actualcode;
memset(sshc, 0, sizeof(struct ssh_conn));
connclose(conn, "SSH session free");
sshc->state = SSH_SESSION_FREE; /* current */
sshc->nextstate = SSH_NO_STATE;
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
case SSH_QUIT:
default:
/* internal error */
sshc->nextstate = SSH_NO_STATE;
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
}
@@ -1999,10 +2042,10 @@ static int myssh_getsock(struct Curl_easy *data,
return bitmap;
}
-static void myssh_block2waitfor(struct connectdata *conn, bool block)
+static void myssh_block2waitfor(struct connectdata *conn,
+ struct ssh_conn *sshc,
+ bool block)
{
- struct ssh_conn *sshc = &conn->proto.sshc;
-
/* If it did not block, or nothing was returned by ssh_get_poll_flags
* have the original set */
conn->waitfor = sshc->orig_waitfor;
@@ -2023,30 +2066,35 @@ static CURLcode myssh_multi_statemach(struct Curl_easy *data,
bool *done)
{
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+ struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY);
bool block; /* we store the status and use that to provide a ssh_getsock()
implementation */
- CURLcode result = myssh_statemach_act(data, &block);
+ CURLcode result;
+ if(!sshc || !sshp)
+ return CURLE_FAILED_INIT;
+ result = myssh_statemach_act(data, sshc, sshp, &block);
*done = (sshc->state == SSH_STOP);
- myssh_block2waitfor(conn, block);
+ myssh_block2waitfor(conn, sshc, block);
return result;
}
static CURLcode myssh_block_statemach(struct Curl_easy *data,
+ struct ssh_conn *sshc,
+ struct SSHPROTO *sshp,
bool disconnect)
{
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
CURLcode result = CURLE_OK;
while((sshc->state != SSH_STOP) && !result) {
bool block;
timediff_t left = 1000;
- struct curltime now = Curl_now();
+ struct curltime now = curlx_now();
- result = myssh_statemach_act(data, &block);
+ result = myssh_statemach_act(data, sshc, sshp, &block);
if(result)
break;
@@ -2077,22 +2125,45 @@ static CURLcode myssh_block_statemach(struct Curl_easy *data,
return result;
}
+static void myssh_easy_dtor(void *key, size_t klen, void *entry)
+{
+ struct SSHPROTO *sshp = entry;
+ (void)key;
+ (void)klen;
+ Curl_safefree(sshp->path);
+ free(sshp);
+}
+
+static void myssh_conn_dtor(void *key, size_t klen, void *entry)
+{
+ struct ssh_conn *sshc = entry;
+ (void)key;
+ (void)klen;
+ sshc_cleanup(sshc);
+ free(sshc);
+}
+
/*
* SSH setup connection
*/
static CURLcode myssh_setup_connection(struct Curl_easy *data,
struct connectdata *conn)
{
- struct SSHPROTO *ssh;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct SSHPROTO *sshp;
+ struct ssh_conn *sshc;
- if(!sshc->initialised) {
- Curl_dyn_init(&sshc->readdir_buf, CURL_PATH_MAX * 2);
- sshc->initialised = TRUE;
- }
+ sshc = calloc(1, sizeof(*sshc));
+ if(!sshc)
+ return CURLE_OUT_OF_MEMORY;
- data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
- if(!ssh)
+ curlx_dyn_init(&sshc->readdir_buf, CURL_PATH_MAX * 2);
+ sshc->initialised = TRUE;
+ if(Curl_conn_meta_set(conn, CURL_META_SSH_CONN, sshc, myssh_conn_dtor))
+ return CURLE_OUT_OF_MEMORY;
+
+ sshp = calloc(1, sizeof(*sshp));
+ if(!sshp ||
+ Curl_meta_set(data, CURL_META_SSH_EASY, sshp, myssh_easy_dtor))
return CURLE_OUT_OF_MEMORY;
return CURLE_OK;
@@ -2107,15 +2178,15 @@ static Curl_send scp_send, sftp_send;
*/
static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
{
- struct ssh_conn *ssh;
CURLcode result;
struct connectdata *conn = data->conn;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+ struct SSHPROTO *ssh = Curl_meta_get(data, CURL_META_SSH_EASY);
curl_socket_t sock = conn->sock[FIRSTSOCKET];
int rc;
- /* initialize per-handle data if not already */
- if(!data->req.p.ssh)
- myssh_setup_connection(data, conn);
+ if(!sshc || !ssh)
+ return CURLE_FAILED_INIT;
/* We default to persistent connections. We set this already in this connect
function to make the reuse checks properly be able to check this bit. */
@@ -2130,10 +2201,8 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
conn->send[FIRSTSOCKET] = sftp_send;
}
- ssh = &conn->proto.sshc;
-
- ssh->ssh_session = ssh_new();
- if(!ssh->ssh_session) {
+ sshc->ssh_session = ssh_new();
+ if(!sshc->ssh_session) {
failf(data, "Failure initialising ssh session");
return CURLE_FAILED_INIT;
}
@@ -2141,23 +2210,23 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
if(conn->bits.ipv6_ip) {
char ipv6[MAX_IPADR_LEN];
msnprintf(ipv6, sizeof(ipv6), "[%s]", conn->host.name);
- rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, ipv6);
+ rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_HOST, ipv6);
}
else
- rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name);
+ rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_HOST, conn->host.name);
if(rc != SSH_OK) {
failf(data, "Could not set remote host");
return CURLE_FAILED_INIT;
}
- rc = ssh_options_parse_config(ssh->ssh_session, NULL);
+ rc = ssh_options_parse_config(sshc->ssh_session, NULL);
if(rc != SSH_OK) {
infof(data, "Could not parse SSH configuration files");
/* ignore */
}
- rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock);
+ rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_FD, &sock);
if(rc != SSH_OK) {
failf(data, "Could not set socket");
return CURLE_FAILED_INIT;
@@ -2165,7 +2234,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
if(conn->user && conn->user[0] != '\0') {
infof(data, "User: %s", conn->user);
- rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user);
+ rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_USER, conn->user);
if(rc != SSH_OK) {
failf(data, "Could not set user");
return CURLE_FAILED_INIT;
@@ -2174,7 +2243,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
infof(data, "Known hosts: %s", data->set.str[STRING_SSH_KNOWNHOSTS]);
- rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS,
+ rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_KNOWNHOSTS,
data->set.str[STRING_SSH_KNOWNHOSTS]);
if(rc != SSH_OK) {
failf(data, "Could not set known hosts file path");
@@ -2183,7 +2252,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
}
if(conn->remote_port) {
- rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_PORT,
+ rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_PORT,
&conn->remote_port);
if(rc != SSH_OK) {
failf(data, "Could not set remote port");
@@ -2192,7 +2261,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
}
if(data->set.ssh_compression) {
- rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_COMPRESSION,
+ rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_COMPRESSION,
"zlib,zlib@openssh.com,none");
if(rc != SSH_OK) {
failf(data, "Could not set compression");
@@ -2200,12 +2269,12 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
}
}
- ssh->privkey = NULL;
- ssh->pubkey = NULL;
+ sshc->privkey = NULL;
+ sshc->pubkey = NULL;
if(data->set.str[STRING_SSH_PUBLIC_KEY]) {
rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY],
- &ssh->pubkey);
+ &sshc->pubkey);
if(rc != SSH_OK) {
failf(data, "Could not load public key file");
return CURLE_FAILED_INIT;
@@ -2215,7 +2284,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
/* we do not verify here, we do it at the state machine,
* after connection */
- state(data, SSH_INIT);
+ myssh_state(data, sshc, SSH_INIT);
result = myssh_multi_statemach(data, done);
@@ -2249,13 +2318,16 @@ CURLcode scp_perform(struct Curl_easy *data,
bool *connected, bool *dophase_done)
{
CURLcode result = CURLE_OK;
+ struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN);
DEBUGF(infof(data, "DO phase starts"));
*dophase_done = FALSE; /* not done yet */
+ if(!sshc)
+ return CURLE_FAILED_INIT;
/* start the first command in the DO phase */
- state(data, SSH_SCP_TRANS_INIT);
+ myssh_state(data, sshc, SSH_SCP_TRANS_INIT);
result = myssh_multi_statemach(data, dophase_done);
@@ -2273,9 +2345,11 @@ 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 = &conn->proto.sshc;
+ 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 */
@@ -2296,10 +2370,17 @@ static CURLcode myssh_do_it(struct Curl_easy *data, bool *done)
return result;
}
-static void sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data)
+static void sshc_cleanup(struct ssh_conn *sshc)
{
- (void)data;
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;
@@ -2338,7 +2419,7 @@ static void sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data)
Curl_safefree(sshc->rsa);
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
- Curl_dyn_free(&sshc->readdir_buf);
+ curlx_dyn_free(&sshc->readdir_buf);
Curl_safefree(sshc->readdir_linkPath);
SSH_STRING_FREE_CHAR(sshc->homedir);
sshc->initialised = FALSE;
@@ -2353,37 +2434,37 @@ static CURLcode scp_disconnect(struct Curl_easy *data,
bool dead_connection)
{
CURLcode result = CURLE_OK;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+ struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY);
(void) dead_connection;
- if(sshc->ssh_session) {
+ if(sshc && sshc->ssh_session && sshp) {
/* only if there is a session still around to use! */
- state(data, SSH_SESSION_DISCONNECT);
+ myssh_state(data, sshc, SSH_SESSION_DISCONNECT);
- result = myssh_block_statemach(data, TRUE);
+ result = myssh_block_statemach(data, sshc, sshp, TRUE);
}
- sshc_cleanup(sshc, data);
return result;
}
/* generic done function for both SCP and SFTP called from their specific
done functions */
-static CURLcode myssh_done(struct Curl_easy *data, CURLcode status)
+static CURLcode myssh_done(struct Curl_easy *data,
+ struct ssh_conn *sshc,
+ CURLcode status)
{
CURLcode result = CURLE_OK;
- struct SSHPROTO *protop = data->req.p.ssh;
+ struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY);
- if(!status) {
+ if(!status && sshp) {
/* run the state-machine */
- result = myssh_block_statemach(data, FALSE);
+ result = myssh_block_statemach(data, sshc, sshp, FALSE);
}
else
result = status;
- if(protop)
- Curl_safefree(protop->path);
if(Curl_pgrsDone(data))
return CURLE_ABORTED_BY_CALLBACK;
@@ -2395,13 +2476,15 @@ static CURLcode myssh_done(struct Curl_easy *data, CURLcode status)
static CURLcode scp_done(struct Curl_easy *data, CURLcode status,
bool premature)
{
+ struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN);
(void) premature; /* not used */
+ if(!sshc)
+ return CURLE_FAILED_INIT;
if(!status)
- state(data, SSH_SCP_DONE);
-
- return myssh_done(data, status);
+ myssh_state(data, sshc, SSH_SCP_DONE);
+ return myssh_done(data, sshc, status);
}
static ssize_t scp_send(struct Curl_easy *data, int sockindex,
@@ -2409,17 +2492,22 @@ static ssize_t scp_send(struct Curl_easy *data, int sockindex,
{
int rc;
struct connectdata *conn = data->conn;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
(void) sockindex; /* we only support SCP on the fixed known primary socket */
- (void) err;
(void)eos;
- rc = ssh_scp_write(conn->proto.sshc.scp_session, mem, len);
+ if(!sshc) {
+ *err = CURLE_FAILED_INIT;
+ return -1;
+ }
+
+ rc = ssh_scp_write(sshc->scp_session, mem, len);
#if 0
/* The following code is misleading, mostly added as wishful thinking
* that libssh at some point will implement non-blocking ssh_scp_write/read.
* Currently rc can only be number of bytes read or SSH_ERROR. */
- myssh_block2waitfor(conn, (rc == SSH_AGAIN));
+ myssh_block2waitfor(conn, sshc, (rc == SSH_AGAIN));
if(rc == SSH_AGAIN) {
*err = CURLE_AGAIN;
@@ -2440,18 +2528,22 @@ static ssize_t scp_recv(struct Curl_easy *data, int sockindex,
{
ssize_t nread;
struct connectdata *conn = data->conn;
- (void) err;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
(void) sockindex; /* we only support SCP on the fixed known primary socket */
+ if(!sshc) {
+ *err = CURLE_FAILED_INIT;
+ return -1;
+ }
/* libssh returns int */
- nread = ssh_scp_read(conn->proto.sshc.scp_session, mem, len);
+ nread = ssh_scp_read(sshc->scp_session, mem, len);
#if 0
/* The following code is misleading, mostly added as wishful thinking
* that libssh at some point will implement non-blocking ssh_scp_write/read.
* Currently rc can only be SSH_OK or SSH_ERROR. */
- myssh_block2waitfor(conn, (nread == SSH_AGAIN));
+ myssh_block2waitfor(conn, sshc, (nread == SSH_AGAIN));
if(nread == SSH_AGAIN) {
*err = CURLE_AGAIN;
nread = -1;
@@ -2479,14 +2571,17 @@ CURLcode sftp_perform(struct Curl_easy *data,
bool *connected,
bool *dophase_done)
{
+ struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN);
CURLcode result = CURLE_OK;
DEBUGF(infof(data, "DO phase starts"));
*dophase_done = FALSE; /* not done yet */
+ if(!sshc)
+ return CURLE_FAILED_INIT;
/* start the first command in the DO phase */
- state(data, SSH_SFTP_QUOTE_INIT);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_INIT);
/* run the state-machine */
result = myssh_multi_statemach(data, dophase_done);
@@ -2518,21 +2613,20 @@ static CURLcode sftp_disconnect(struct Curl_easy *data,
struct connectdata *conn,
bool dead_connection)
{
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+ struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY);
CURLcode result = CURLE_OK;
(void) dead_connection;
DEBUGF(infof(data, "SSH DISCONNECT starts now"));
- if(conn->proto.sshc.ssh_session) {
+ if(sshc && sshc->ssh_session && sshp) {
/* only if there is a session still around to use! */
- state(data, SSH_SFTP_SHUTDOWN);
- result = myssh_block_statemach(data, TRUE);
+ myssh_state(data, sshc, SSH_SFTP_SHUTDOWN);
+ result = myssh_block_statemach(data, sshc, sshp, TRUE);
}
DEBUGF(infof(data, "SSH DISCONNECT is done"));
- sshc_cleanup(sshc, data);
-
return result;
}
@@ -2540,17 +2634,19 @@ static CURLcode sftp_done(struct Curl_easy *data, CURLcode status,
bool premature)
{
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+ if(!sshc)
+ return CURLE_FAILED_INIT;
if(!status) {
/* Post quote commands are executed after the SFTP_CLOSE state to avoid
errors that could happen due to open file handles during POSTQUOTE
operation */
if(!premature && data->set.postquote && !conn->bits.retry)
sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
}
- return myssh_done(data, status);
+ return myssh_done(data, sshc, status);
}
/* return number of sent bytes */
@@ -2560,28 +2656,33 @@ static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
{
ssize_t nwrite;
struct connectdata *conn = data->conn;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
(void)sockindex;
(void)eos;
+ if(!sshc) {
+ *err = CURLE_FAILED_INIT;
+ return -1;
+ }
/* limit the writes to the maximum specified in Section 3 of
* https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02
*/
if(len > 32768)
len = 32768;
#if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0)
- switch(conn->proto.sshc.sftp_send_state) {
+ switch(sshc->sftp_send_state) {
case 0:
- sftp_file_set_nonblocking(conn->proto.sshc.sftp_file);
- if(sftp_aio_begin_write(conn->proto.sshc.sftp_file, mem, len,
- &conn->proto.sshc.sftp_aio) == SSH_ERROR) {
+ sftp_file_set_nonblocking(sshc->sftp_file);
+ if(sftp_aio_begin_write(sshc->sftp_file, mem, len,
+ &sshc->sftp_aio) == SSH_ERROR) {
*err = CURLE_SEND_ERROR;
return -1;
}
- conn->proto.sshc.sftp_send_state = 1;
+ sshc->sftp_send_state = 1;
FALLTHROUGH();
case 1:
- nwrite = sftp_aio_wait_write(&conn->proto.sshc.sftp_aio);
- myssh_block2waitfor(conn, (nwrite == SSH_AGAIN) ? TRUE : FALSE);
+ nwrite = sftp_aio_wait_write(&sshc->sftp_aio);
+ myssh_block2waitfor(conn, sshc, (nwrite == SSH_AGAIN) ? TRUE : FALSE);
if(nwrite == SSH_AGAIN) {
*err = CURLE_AGAIN;
return 0;
@@ -2590,20 +2691,20 @@ static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
*err = CURLE_SEND_ERROR;
return -1;
}
- if(conn->proto.sshc.sftp_aio) {
- sftp_aio_free(conn->proto.sshc.sftp_aio);
- conn->proto.sshc.sftp_aio = NULL;
+ if(sshc->sftp_aio) {
+ sftp_aio_free(sshc->sftp_aio);
+ sshc->sftp_aio = NULL;
}
- conn->proto.sshc.sftp_send_state = 0;
+ sshc->sftp_send_state = 0;
return nwrite;
default:
/* we never reach here */
return -1;
}
#else
- nwrite = sftp_write(conn->proto.sshc.sftp_file, mem, len);
+ nwrite = sftp_write(sshc->sftp_file, mem, len);
- myssh_block2waitfor(conn, FALSE);
+ myssh_block2waitfor(conn, sshc, FALSE);
#if 0 /* not returned by libssh on write */
if(nwrite == SSH_AGAIN) {
@@ -2630,29 +2731,31 @@ static ssize_t sftp_recv(struct Curl_easy *data, int sockindex,
{
ssize_t nread;
struct connectdata *conn = data->conn;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
(void)sockindex;
DEBUGASSERT(len < CURL_MAX_READ_SIZE);
+ if(!sshc) {
+ *err = CURLE_FAILED_INIT;
+ return -1;
+ }
- switch(conn->proto.sshc.sftp_recv_state) {
+ switch(sshc->sftp_recv_state) {
case 0:
- conn->proto.sshc.sftp_file_index =
- sftp_async_read_begin(conn->proto.sshc.sftp_file,
- (uint32_t)len);
- if(conn->proto.sshc.sftp_file_index < 0) {
+ sshc->sftp_file_index =
+ sftp_async_read_begin(sshc->sftp_file, (uint32_t)len);
+ if(sshc->sftp_file_index < 0) {
*err = CURLE_RECV_ERROR;
return -1;
}
FALLTHROUGH();
case 1:
- conn->proto.sshc.sftp_recv_state = 1;
-
- nread = sftp_async_read(conn->proto.sshc.sftp_file,
- mem, (uint32_t)len,
- (uint32_t)conn->proto.sshc.sftp_file_index);
+ sshc->sftp_recv_state = 1;
+ nread = sftp_async_read(sshc->sftp_file, mem, (uint32_t)len,
+ (uint32_t)sshc->sftp_file_index);
- myssh_block2waitfor(conn, (nread == SSH_AGAIN));
+ myssh_block2waitfor(conn, sshc, (nread == SSH_AGAIN));
if(nread == SSH_AGAIN) {
*err = CURLE_AGAIN;
@@ -2663,7 +2766,7 @@ static ssize_t sftp_recv(struct Curl_easy *data, int sockindex,
return -1;
}
- conn->proto.sshc.sftp_recv_state = 0;
+ sshc->sftp_recv_state = 0;
return nread;
default:
@@ -2672,12 +2775,11 @@ static ssize_t sftp_recv(struct Curl_easy *data, int sockindex,
}
}
-static void sftp_quote(struct Curl_easy *data)
+static void sftp_quote(struct Curl_easy *data,
+ struct ssh_conn *sshc,
+ struct SSHPROTO *sshp)
{
const char *cp;
- struct connectdata *conn = data->conn;
- struct SSHPROTO *protop = data->req.p.ssh;
- struct ssh_conn *sshc = &conn->proto.sshc;
CURLcode result;
/*
@@ -2698,11 +2800,10 @@ static void sftp_quote(struct Curl_easy *data)
if(strcasecompare("pwd", cmd)) {
/* output debug output if that is requested */
- char *tmp = aprintf("257 \"%s\" is current directory.\n",
- protop->path);
+ char *tmp = aprintf("257 \"%s\" is current directory.\n", sshp->path);
if(!tmp) {
sshc->actualcode = CURLE_OUT_OF_MEMORY;
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
return;
}
@@ -2715,12 +2816,12 @@ static void sftp_quote(struct Curl_easy *data)
result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
free(tmp);
if(result) {
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = result;
}
else
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
return;
}
@@ -2731,7 +2832,7 @@ static void sftp_quote(struct Curl_easy *data)
cp = strchr(cmd, ' ');
if(!cp) {
failf(data, "Syntax error in SFTP command. Supply parameter(s)");
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
return;
@@ -2747,7 +2848,7 @@ static void sftp_quote(struct Curl_easy *data)
failf(data, "Out of memory");
else
failf(data, "Syntax error: Bad first parameter");
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = result;
return;
@@ -2776,13 +2877,13 @@ static void sftp_quote(struct Curl_easy *data)
failf(data, "Syntax error in chgrp/chmod/chown/atime/mtime: "
"Bad second parameter");
Curl_safefree(sshc->quote_path1);
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = result;
return;
}
sshc->quote_attrs = NULL;
- state(data, SSH_SFTP_QUOTE_STAT);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_STAT);
return;
}
if(!strncmp(cmd, "ln ", 3) ||
@@ -2797,17 +2898,17 @@ static void sftp_quote(struct Curl_easy *data)
else
failf(data, "Syntax error in ln/symlink: Bad second parameter");
Curl_safefree(sshc->quote_path1);
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = result;
return;
}
- state(data, SSH_SFTP_QUOTE_SYMLINK);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_SYMLINK);
return;
}
else if(!strncmp(cmd, "mkdir ", 6)) {
/* create dir */
- state(data, SSH_SFTP_QUOTE_MKDIR);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_MKDIR);
return;
}
else if(!strncmp(cmd, "rename ", 7)) {
@@ -2821,26 +2922,26 @@ static void sftp_quote(struct Curl_easy *data)
else
failf(data, "Syntax error in rename: Bad second parameter");
Curl_safefree(sshc->quote_path1);
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = result;
return;
}
- state(data, SSH_SFTP_QUOTE_RENAME);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_RENAME);
return;
}
else if(!strncmp(cmd, "rmdir ", 6)) {
/* delete dir */
- state(data, SSH_SFTP_QUOTE_RMDIR);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_RMDIR);
return;
}
else if(!strncmp(cmd, "rm ", 3)) {
- state(data, SSH_SFTP_QUOTE_UNLINK);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_UNLINK);
return;
}
#ifdef HAS_STATVFS_SUPPORT
else if(!strncmp(cmd, "statvfs ", 8)) {
- state(data, SSH_SFTP_QUOTE_STATVFS);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_STATVFS);
return;
}
#endif
@@ -2848,15 +2949,14 @@ static void sftp_quote(struct Curl_easy *data)
failf(data, "Unknown SFTP command");
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
}
-static void sftp_quote_stat(struct Curl_easy *data)
+static void sftp_quote_stat(struct Curl_easy *data,
+ struct ssh_conn *sshc)
{
- struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
char *cmd = sshc->quote_item->data;
sshc->acceptfail = FALSE;
@@ -2883,7 +2983,7 @@ static void sftp_quote_stat(struct Curl_easy *data)
Curl_safefree(sshc->quote_path2);
failf(data, "Attempt to get SFTP stats failed: %d",
sftp_get_error(sshc->sftp_session));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
return;
@@ -2893,14 +2993,14 @@ static void sftp_quote_stat(struct Curl_easy *data)
if(!strncmp(cmd, "chgrp", 5)) {
const char *p = sshc->quote_path1;
curl_off_t gid;
- (void)Curl_str_number(&p, &gid, UINT_MAX);
+ (void)curlx_str_number(&p, &gid, UINT_MAX);
sshc->quote_attrs->gid = (uint32_t)gid;
if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
!sshc->acceptfail) {
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
failf(data, "Syntax error: chgrp gid not a number");
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
return;
@@ -2910,11 +3010,11 @@ static void sftp_quote_stat(struct Curl_easy *data)
else if(!strncmp(cmd, "chmod", 5)) {
curl_off_t perms;
const char *p = sshc->quote_path1;
- if(Curl_str_octal(&p, &perms, 07777)) {
+ if(curlx_str_octal(&p, &perms, 07777)) {
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
failf(data, "Syntax error: chmod permissions not a number");
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
return;
@@ -2925,13 +3025,13 @@ static void sftp_quote_stat(struct Curl_easy *data)
else if(!strncmp(cmd, "chown", 5)) {
const char *p = sshc->quote_path1;
curl_off_t uid;
- (void)Curl_str_number(&p, &uid, UINT_MAX);
+ (void)curlx_str_number(&p, &uid, UINT_MAX);
if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
!sshc->acceptfail) {
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
failf(data, "Syntax error: chown uid not a number");
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
return;
@@ -2955,7 +3055,7 @@ static void sftp_quote_stat(struct Curl_easy *data)
if(fail) {
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
return;
@@ -2969,7 +3069,7 @@ static void sftp_quote_stat(struct Curl_easy *data)
}
/* Now send the completed structure... */
- state(data, SSH_SFTP_QUOTE_SETSTAT);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_SETSTAT);
return;
}