aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/ssh.c2933
1 files changed, 1469 insertions, 1464 deletions
diff --git a/lib/ssh.c b/lib/ssh.c
index a93e440bc..71a8de386 100644
--- a/lib/ssh.c
+++ b/lib/ssh.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -459,10 +459,10 @@ static int sshkeycallback(CURL *easy,
#endif
/*
- * ssh_statemach_act() runs the SSH statemachine "one round" and returns. 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
+ * 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 libssh2 function returns LIBSSH2_ERROR_EAGAIN
+ * meaning it wants to be called again when the socket is ready
*/
static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
@@ -481,1194 +481,1181 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
int seekerr = CURL_SEEKFUNC_OK;
*block = 0; /* we're not blocking by default */
- switch(sshc->state) {
- case SSH_S_STARTUP:
- sshc->secondCreateDirs = 0;
- sshc->nextstate = SSH_NO_STATE;
- sshc->actualcode = CURLE_OK;
+ do {
- rc = libssh2_session_startup(sshc->ssh_session, sock);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
- }
- else if(rc) {
- failf(data, "Failure establishing ssh session");
- state(conn, SSH_SESSION_FREE);
- sshc->actualcode = CURLE_FAILED_INIT;
- break;
- }
+ switch(sshc->state) {
+ case SSH_S_STARTUP:
+ sshc->secondCreateDirs = 0;
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_OK;
- /* Set libssh2 to non-blocking, since everything internally is
- non-blocking */
- libssh2_session_set_blocking(sshc->ssh_session, 0);
+ rc = libssh2_session_startup(sshc->ssh_session, sock);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc) {
+ failf(data, "Failure establishing ssh session");
+ state(conn, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_FAILED_INIT;
+ break;
+ }
+
+ /* Set libssh2 to non-blocking, since everything internally is
+ non-blocking */
+ libssh2_session_set_blocking(sshc->ssh_session, 0);
- state(conn, SSH_HOSTKEY);
+ state(conn, SSH_HOSTKEY);
- /* fall-through */
- case SSH_HOSTKEY:
+ /* fall-through */
+ case SSH_HOSTKEY:
#ifdef CURL_LIBSSH2_DEBUG
- /*
- * Before we authenticate we should check the hostkey's fingerprint
- * against our known hosts. How that is handled (reading from file,
- * whatever) is up to us. As for know not much is implemented, besides
- * showing how to get the fingerprint.
- */
- fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
- LIBSSH2_HOSTKEY_HASH_MD5);
-
- /* The fingerprint points to static storage (!), don't free() it. */
- infof(data, "Fingerprint: ");
- for (rc = 0; rc < 16; rc++) {
- infof(data, "%02X ", (unsigned char) fingerprint[rc]);
- }
- infof(data, "\n");
-#endif /* CURL_LIBSSH2_DEBUG */
+ /*
+ * Before we authenticate we should check the hostkey's fingerprint
+ * against our known hosts. How that is handled (reading from file,
+ * whatever) is up to us. As for know not much is implemented, besides
+ * showing how to get the fingerprint.
+ */
+ fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
+ LIBSSH2_HOSTKEY_HASH_MD5);
- /* Before we authenticate we check the hostkey's MD5 fingerprint
- * against a known fingerprint, if available. This implementation pulls
- * it from the curl option.
- */
- if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] &&
- strlen(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) == 32) {
- char buf[33];
- host_public_key_md5 = libssh2_hostkey_hash(sshc->ssh_session,
- LIBSSH2_HOSTKEY_HASH_MD5);
- for (i = 0; i < 16; i++)
- snprintf(&buf[i*2], 3, "%02x",
- (unsigned char) host_public_key_md5[i]);
- if(!strequal(buf, data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5])) {
- failf(data,
- "Denied establishing ssh session: mismatch md5 fingerprint. "
- "Remote %s is not equal to %s",
- buf, data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]);
- state(conn, SSH_SESSION_FREE);
- sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
- break;
+ /* The fingerprint points to static storage (!), don't free() it. */
+ infof(data, "Fingerprint: ");
+ for (rc = 0; rc < 16; rc++) {
+ infof(data, "%02X ", (unsigned char) fingerprint[rc]);
}
- }
+ infof(data, "\n");
+#endif /* CURL_LIBSSH2_DEBUG */
-#ifdef HAVE_LIBSSH2_KNOWNHOST_API
- if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
- /* we're asked to verify the host against a file */
- int keytype;
- size_t keylen;
- const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
- &keylen, &keytype);
- int keycheck;
- int keybit;
-
- if(remotekey) {
- /*
- * A subject to figure out is what host name we need to pass in here.
- * What host name does OpenSSH store in its file if an IDN name is
- * used?
- */
- struct libssh2_knownhost *host;
- enum curl_khmatch keymatch;
- curl_sshkeycallback func =
- data->set.ssh_keyfunc?data->set.ssh_keyfunc:sshkeycallback;
- struct curl_khkey knownkey;
- struct curl_khkey *knownkeyp = NULL;
- struct curl_khkey foundkey;
-
- keybit = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
- LIBSSH2_KNOWNHOST_KEY_SSHRSA:LIBSSH2_KNOWNHOST_KEY_SSHDSS;
-
- keycheck = libssh2_knownhost_check(sshc->kh,
- conn->host.name,
- remotekey, keylen,
- LIBSSH2_KNOWNHOST_TYPE_PLAIN|
- LIBSSH2_KNOWNHOST_KEYENC_RAW|
- keybit,
- &host);
-
- infof(data, "SSH host check: %d, key: %s\n", keycheck,
- (keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)?
- host->key:"<none>");
-
- /* setup 'knownkey' */
- if(keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH) {
- knownkey.key = host->key;
- knownkey.len = 0;
- knownkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
- CURLKHTYPE_RSA : CURLKHTYPE_DSS;
- knownkeyp = &knownkey;
+ /* Before we authenticate we check the hostkey's MD5 fingerprint
+ * against a known fingerprint, if available. This implementation pulls
+ * it from the curl option.
+ */
+ if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] &&
+ strlen(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) == 32) {
+ char buf[33];
+ host_public_key_md5 = libssh2_hostkey_hash(sshc->ssh_session,
+ LIBSSH2_HOSTKEY_HASH_MD5);
+ for (i = 0; i < 16; i++)
+ snprintf(&buf[i*2], 3, "%02x",
+ (unsigned char) host_public_key_md5[i]);
+ if(!strequal(buf, data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5])) {
+ failf(data,
+ "Denied establishing ssh session: mismatch md5 fingerprint. "
+ "Remote %s is not equal to %s",
+ buf, data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]);
+ state(conn, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+ break;
}
+ }
- /* setup 'foundkey' */
- foundkey.key = remotekey;
- foundkey.len = keylen;
- foundkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
- CURLKHTYPE_RSA : CURLKHTYPE_DSS;
-
- /*
- * if any of the LIBSSH2_KNOWNHOST_CHECK_* defines and the
- * curl_khmatch enum are ever modified, we need to introduce a
- * translation table here!
- */
- keymatch = (enum curl_khmatch)keycheck;
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+ if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
+ /* we're asked to verify the host against a file */
+ int keytype;
+ size_t keylen;
+ const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
+ &keylen, &keytype);
+ int keycheck;
+ int keybit;
+
+ if(remotekey) {
+ /*
+ * A subject to figure out is what host name we need to pass in here.
+ * What host name does OpenSSH store in its file if an IDN name is
+ * used?
+ */
+ struct libssh2_knownhost *host;
+ enum curl_khmatch keymatch;
+ curl_sshkeycallback func =
+ data->set.ssh_keyfunc?data->set.ssh_keyfunc:sshkeycallback;
+ struct curl_khkey knownkey;
+ struct curl_khkey *knownkeyp = NULL;
+ struct curl_khkey foundkey;
+
+ keybit = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
+ LIBSSH2_KNOWNHOST_KEY_SSHRSA:LIBSSH2_KNOWNHOST_KEY_SSHDSS;
+
+ keycheck = libssh2_knownhost_check(sshc->kh,
+ conn->host.name,
+ remotekey, keylen,
+ LIBSSH2_KNOWNHOST_TYPE_PLAIN|
+ LIBSSH2_KNOWNHOST_KEYENC_RAW|
+ keybit,
+ &host);
+
+ infof(data, "SSH host check: %d, key: %s\n", keycheck,
+ (keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)?
+ host->key:"<none>");
+
+ /* setup 'knownkey' */
+ if(keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH) {
+ knownkey.key = host->key;
+ knownkey.len = 0;
+ knownkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
+ CURLKHTYPE_RSA : CURLKHTYPE_DSS;
+ knownkeyp = &knownkey;
+ }
- /* Ask the callback how to behave */
- rc = func(data, knownkeyp, /* from the knownhosts file */
- &foundkey, /* from the remote host */
- keymatch, data->set.ssh_keyfunc_userp);
- }
- else
- /* no remotekey means failure! */
- rc = CURLKHSTAT_REJECT;
+ /* setup 'foundkey' */
+ foundkey.key = remotekey;
+ foundkey.len = keylen;
+ foundkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
+ CURLKHTYPE_RSA : CURLKHTYPE_DSS;
- switch(rc) {
- default: /* unknown return codes will equal reject */
- case CURLKHSTAT_REJECT:
- state(conn, SSH_SESSION_FREE);
- case CURLKHSTAT_DEFER:
- /* DEFER means bail out but keep the SSH_HOSTKEY state */
- result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
- break;
- case CURLKHSTAT_FINE:
- case CURLKHSTAT_FINE_ADD_TO_FILE:
- /* proceed */
- if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) {
- /* the found host+key didn't match but has been told to be fine
- anyway so we add it in memory */
- int addrc = libssh2_knownhost_add(sshc->kh,
- conn->host.name, NULL,
- remotekey, keylen,
- LIBSSH2_KNOWNHOST_TYPE_PLAIN|
- LIBSSH2_KNOWNHOST_KEYENC_RAW|
- keybit, NULL);
- if(addrc)
- infof(data, "Warning adding the known host %s failed!\n",
- conn->host.name);
- else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE) {
- /* now we write the entire in-memory list of known hosts to the
- known_hosts file */
- int wrc =
- libssh2_knownhost_writefile(sshc->kh,
- data->set.str[STRING_SSH_KNOWNHOSTS],
- LIBSSH2_KNOWNHOST_FILE_OPENSSH);
- if(wrc) {
- infof(data, "Warning, writing %s failed!\n",
- data->set.str[STRING_SSH_KNOWNHOSTS]);
+ /*
+ * if any of the LIBSSH2_KNOWNHOST_CHECK_* defines and the
+ * curl_khmatch enum are ever modified, we need to introduce a
+ * translation table here!
+ */
+ keymatch = (enum curl_khmatch)keycheck;
+
+ /* Ask the callback how to behave */
+ rc = func(data, knownkeyp, /* from the knownhosts file */
+ &foundkey, /* from the remote host */
+ keymatch, data->set.ssh_keyfunc_userp);
+ }
+ else
+ /* no remotekey means failure! */
+ rc = CURLKHSTAT_REJECT;
+
+ switch(rc) {
+ default: /* unknown return codes will equal reject */
+ case CURLKHSTAT_REJECT:
+ state(conn, SSH_SESSION_FREE);
+ case CURLKHSTAT_DEFER:
+ /* DEFER means bail out but keep the SSH_HOSTKEY state */
+ result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+ break;
+ case CURLKHSTAT_FINE:
+ case CURLKHSTAT_FINE_ADD_TO_FILE:
+ /* proceed */
+ if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) {
+ /* the found host+key didn't match but has been told to be fine
+ anyway so we add it in memory */
+ int addrc = libssh2_knownhost_add(sshc->kh,
+ conn->host.name, NULL,
+ remotekey, keylen,
+ LIBSSH2_KNOWNHOST_TYPE_PLAIN|
+ LIBSSH2_KNOWNHOST_KEYENC_RAW|
+ keybit, NULL);
+ if(addrc)
+ infof(data, "Warning adding the known host %s failed!\n",
+ conn->host.name);
+ else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE) {
+ /* now we write the entire in-memory list of known hosts to the
+ known_hosts file */
+ int wrc =
+ libssh2_knownhost_writefile(sshc->kh,
+ data->set.str[STRING_SSH_KNOWNHOSTS],
+ LIBSSH2_KNOWNHOST_FILE_OPENSSH);
+ if(wrc) {
+ infof(data, "Warning, writing %s failed!\n",
+ data->set.str[STRING_SSH_KNOWNHOSTS]);
+ }
}
}
+ break;
}
- break;
}
- }
#endif /* HAVE_LIBSSH2_KNOWNHOST_API */
- state(conn, SSH_AUTHLIST);
- break;
+ state(conn, SSH_AUTHLIST);
+ break;
- case SSH_AUTHLIST:
- /*
- * Figure out authentication methods
- * NB: As soon as we have provided a username to an openssh server we
- * must never change it later. Thus, always specify the correct username
- * here, even though the libssh2 docs kind of indicate that it should be
- * possible to get a 'generic' list (not user-specific) of authentication
- * methods, presumably with a blank username. That won't work in my
- * experience.
- * So always specify it here.
- */
- sshc->authlist = libssh2_userauth_list(sshc->ssh_session,
- conn->user,
- strlen(conn->user));
-
- if(!sshc->authlist) {
- if((err = libssh2_session_last_errno(sshc->ssh_session)) ==
- LIBSSH2_ERROR_EAGAIN) {
- rc = LIBSSH2_ERROR_EAGAIN;
- break;
- }
- else {
- state(conn, SSH_SESSION_FREE);
- sshc->actualcode = libssh2_session_error_to_CURLE(err);
- break;
+ case SSH_AUTHLIST:
+ /*
+ * Figure out authentication methods
+ * NB: As soon as we have provided a username to an openssh server we
+ * must never change it later. Thus, always specify the correct username
+ * here, even though the libssh2 docs kind of indicate that it should be
+ * possible to get a 'generic' list (not user-specific) of authentication
+ * methods, presumably with a blank username. That won't work in my
+ * experience.
+ * So always specify it here.
+ */
+ sshc->authlist = libssh2_userauth_list(sshc->ssh_session,
+ conn->user,
+ strlen(conn->user));
+
+ if(!sshc->authlist) {
+ if((err = libssh2_session_last_errno(sshc->ssh_session)) ==
+ LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+ else {
+ state(conn, SSH_SESSION_FREE);
+ sshc->actualcode = libssh2_session_error_to_CURLE(err);
+ break;
+ }
}
- }
- infof(data, "SSH authentication methods available: %s\n", sshc->authlist);
+ infof(data, "SSH authentication methods available: %s\n", sshc->authlist);
- state(conn, SSH_AUTH_PKEY_INIT);
- break;
+ state(conn, SSH_AUTH_PKEY_INIT);
+ break;
- case SSH_AUTH_PKEY_INIT:
- /*
- * Check the supported auth types in the order I feel is most secure
- * with the requested type of authentication
- */
- sshc->authed = FALSE;
+ case SSH_AUTH_PKEY_INIT:
+ /*
+ * Check the supported auth types in the order I feel is most secure
+ * with the requested type of authentication
+ */
+ sshc->authed = FALSE;
- if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) &&
- (strstr(sshc->authlist, "publickey") != NULL)) {
- char *home;
+ if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) &&
+ (strstr(sshc->authlist, "publickey") != NULL)) {
+ char *home;
- sshc->rsa_pub = sshc->rsa = NULL;
+ sshc->rsa_pub = sshc->rsa = NULL;
- /* To ponder about: should really the lib be messing about with the
- HOME environment variable etc? */
- home = curl_getenv("HOME");
+ /* To ponder about: should really the lib be messing about with the
+ HOME environment variable etc? */
+ home = curl_getenv("HOME");
- if(data->set.str[STRING_SSH_PUBLIC_KEY])
- sshc->rsa_pub = aprintf("%s", data->set.str[STRING_SSH_PUBLIC_KEY]);
- else if(home)
- sshc->rsa_pub = aprintf("%s/.ssh/id_dsa.pub", home);
- else
- /* as a final resort, try current dir! */
- sshc->rsa_pub = strdup("id_dsa.pub");
+ if(data->set.str[STRING_SSH_PUBLIC_KEY])
+ sshc->rsa_pub = aprintf("%s", data->set.str[STRING_SSH_PUBLIC_KEY]);
+ else if(home)
+ sshc->rsa_pub = aprintf("%s/.ssh/id_dsa.pub", home);
+ else
+ /* as a final resort, try current dir! */
+ sshc->rsa_pub = strdup("id_dsa.pub");
- if(sshc->rsa_pub == NULL) {
- Curl_safefree(home);
- home = NULL;
- state(conn, SSH_SESSION_FREE);
- sshc->actualcode = CURLE_OUT_OF_MEMORY;
- break;
- }
+ if(sshc->rsa_pub == NULL) {
+ Curl_safefree(home);
+ home = NULL;
+ state(conn, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
- if(data->set.str[STRING_SSH_PRIVATE_KEY])
- sshc->rsa = aprintf("%s", data->set.str[STRING_SSH_PRIVATE_KEY]);
- else if(home)
- sshc->rsa = aprintf("%s/.ssh/id_dsa", home);
- else
- /* as a final resort, try current dir! */
- sshc->rsa = strdup("id_dsa");
+ if(data->set.str[STRING_SSH_PRIVATE_KEY])
+ sshc->rsa = aprintf("%s", data->set.str[STRING_SSH_PRIVATE_KEY]);
+ else if(home)
+ sshc->rsa = aprintf("%s/.ssh/id_dsa", home);
+ else
+ /* as a final resort, try current dir! */
+ sshc->rsa = strdup("id_dsa");
+
+ if(sshc->rsa == NULL) {
+ Curl_safefree(home);
+ home = NULL;
+ Curl_safefree(sshc->rsa_pub);
+ sshc->rsa_pub = NULL;
+ state(conn, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+
+ sshc->passphrase = data->set.str[STRING_KEY_PASSWD];
+ if(!sshc->passphrase)
+ sshc->passphrase = "";
- if(sshc->rsa == NULL) {
Curl_safefree(home);
home = NULL;
- Curl_safefree(sshc->rsa_pub);
- sshc->rsa_pub = NULL;
- state(conn, SSH_SESSION_FREE);
- sshc->actualcode = CURLE_OUT_OF_MEMORY;
- break;
- }
-
- sshc->passphrase = data->set.str[STRING_KEY_PASSWD];
- if(!sshc->passphrase)
- sshc->passphrase = "";
-
- Curl_safefree(home);
- home = NULL;
-
- infof(data, "Using ssh public key file %s\n", sshc->rsa_pub);
- infof(data, "Using ssh private key file %s\n", sshc->rsa);
- state(conn, SSH_AUTH_PKEY);
- }
- else {
- state(conn, SSH_AUTH_PASS_INIT);
- }
- break;
+ infof(data, "Using ssh public key file %s\n", sshc->rsa_pub);
+ infof(data, "Using ssh private key file %s\n", sshc->rsa);
- case SSH_AUTH_PKEY:
- /* The function below checks if the files exists, no need to stat() here.
- */
- rc = libssh2_userauth_publickey_fromfile(sshc->ssh_session,
- conn->user, sshc->rsa_pub,
- sshc->rsa, sshc->passphrase);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
+ state(conn, SSH_AUTH_PKEY);
+ }
+ else {
+ state(conn, SSH_AUTH_PASS_INIT);
+ }
break;
- }
- Curl_safefree(sshc->rsa_pub);
- sshc->rsa_pub = NULL;
- Curl_safefree(sshc->rsa);
- sshc->rsa = NULL;
-
- if(rc == 0) {
- sshc->authed = TRUE;
- infof(data, "Initialized SSH public key authentication\n");
- state(conn, SSH_AUTH_DONE);
- }
- else {
- char *err_msg;
- (void)libssh2_session_last_error(sshc->ssh_session,
- &err_msg, NULL, 0);
- infof(data, "SSH public key authentication failed: %s\n", err_msg);
- state(conn, SSH_AUTH_PASS_INIT);
- }
- break;
+ case SSH_AUTH_PKEY:
+ /* The function below checks if the files exists, no need to stat() here.
+ */
+ rc = libssh2_userauth_publickey_fromfile(sshc->ssh_session,
+ conn->user, sshc->rsa_pub,
+ sshc->rsa, sshc->passphrase);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
- case SSH_AUTH_PASS_INIT:
- if((data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD) &&
- (strstr(sshc->authlist, "password") != NULL)) {
- state(conn, SSH_AUTH_PASS);
- }
- else {
- state(conn, SSH_AUTH_HOST_INIT);
- }
- break;
+ Curl_safefree(sshc->rsa_pub);
+ sshc->rsa_pub = NULL;
+ Curl_safefree(sshc->rsa);
+ sshc->rsa = NULL;
- case SSH_AUTH_PASS:
- rc = libssh2_userauth_password(sshc->ssh_session, conn->user,
- conn->passwd);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
+ if(rc == 0) {
+ sshc->authed = TRUE;
+ infof(data, "Initialized SSH public key authentication\n");
+ state(conn, SSH_AUTH_DONE);
+ }
+ else {
+ char *err_msg;
+ (void)libssh2_session_last_error(sshc->ssh_session,
+ &err_msg, NULL, 0);
+ infof(data, "SSH public key authentication failed: %s\n", err_msg);
+ state(conn, SSH_AUTH_PASS_INIT);
+ }
break;
- }
- else if(rc == 0) {
- sshc->authed = TRUE;
- infof(data, "Initialized password authentication\n");
- state(conn, SSH_AUTH_DONE);
- }
- else {
- state(conn, SSH_AUTH_HOST_INIT);
- }
- break;
-
- case SSH_AUTH_HOST_INIT:
- if((data->set.ssh_auth_types & CURLSSH_AUTH_HOST) &&
- (strstr(sshc->authlist, "hostbased") != NULL)) {
- state(conn, SSH_AUTH_HOST);
- }
- else {
- state(conn, SSH_AUTH_KEY_INIT);
- }
- break;
-
- case SSH_AUTH_HOST:
- state(conn, SSH_AUTH_KEY_INIT);
- break;
-
- case SSH_AUTH_KEY_INIT:
- if((data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD)
- && (strstr(sshc->authlist, "keyboard-interactive") != NULL)) {
- state(conn, SSH_AUTH_KEY);
- }
- else {
- state(conn, SSH_AUTH_DONE);
- }
- break;
- case SSH_AUTH_KEY:
- /* Authentication failed. Continue with keyboard-interactive now. */
- rc = libssh2_userauth_keyboard_interactive_ex(sshc->ssh_session,
- conn->user,
- strlen(conn->user),
- &kbd_callback);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
+ case SSH_AUTH_PASS_INIT:
+ if((data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD) &&
+ (strstr(sshc->authlist, "password") != NULL)) {
+ state(conn, SSH_AUTH_PASS);
+ }
+ else {
+ state(conn, SSH_AUTH_HOST_INIT);
+ }
break;
- }
- else if(rc == 0) {
- sshc->authed = TRUE;
- infof(data, "Initialized keyboard interactive authentication\n");
- }
- state(conn, SSH_AUTH_DONE);
- break;
- case SSH_AUTH_DONE:
- if(!sshc->authed) {
- failf(data, "Authentication failure");
- state(conn, SSH_SESSION_FREE);
- sshc->actualcode = CURLE_LOGIN_DENIED;
+ case SSH_AUTH_PASS:
+ rc = libssh2_userauth_password(sshc->ssh_session, conn->user,
+ conn->passwd);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc == 0) {
+ sshc->authed = TRUE;
+ infof(data, "Initialized password authentication\n");
+ state(conn, SSH_AUTH_DONE);
+ }
+ else {
+ state(conn, SSH_AUTH_HOST_INIT);
+ }
break;
- }
- /*
- * At this point we have an authenticated ssh session.
- */
- infof(data, "Authentication complete\n");
-
- Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSH is connected */
+ case SSH_AUTH_HOST_INIT:
+ if((data->set.ssh_auth_types & CURLSSH_AUTH_HOST) &&
+ (strstr(sshc->authlist, "hostbased") != NULL)) {
+ state(conn, SSH_AUTH_HOST);
+ }
+ else {
+ state(conn, SSH_AUTH_KEY_INIT);
+ }
+ break;
- conn->sockfd = sock;
- conn->writesockfd = CURL_SOCKET_BAD;
+ case SSH_AUTH_HOST:
+ state(conn, SSH_AUTH_KEY_INIT);
+ break;
- if(conn->protocol == PROT_SFTP) {
- state(conn, SSH_SFTP_INIT);
+ case SSH_AUTH_KEY_INIT:
+ if((data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD)
+ && (strstr(sshc->authlist, "keyboard-interactive") != NULL)) {
+ state(conn, SSH_AUTH_KEY);
+ }
+ else {
+ state(conn, SSH_AUTH_DONE);
+ }
break;
- }
- infof(data, "SSH CONNECT phase done\n");
- state(conn, SSH_STOP);
- break;
- case SSH_SFTP_INIT:
- /*
- * Start the libssh2 sftp session
- */
- sshc->sftp_session = libssh2_sftp_init(sshc->ssh_session);
- if(!sshc->sftp_session) {
- if(libssh2_session_last_errno(sshc->ssh_session) ==
- LIBSSH2_ERROR_EAGAIN) {
- rc = LIBSSH2_ERROR_EAGAIN;
+ case SSH_AUTH_KEY:
+ /* Authentication failed. Continue with keyboard-interactive now. */
+ rc = libssh2_userauth_keyboard_interactive_ex(sshc->ssh_session,
+ conn->user,
+ strlen(conn->user),
+ &kbd_callback);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
break;
}
- else {
- char *err_msg;
+ else if(rc == 0) {
+ sshc->authed = TRUE;
+ infof(data, "Initialized keyboard interactive authentication\n");
+ }
+ state(conn, SSH_AUTH_DONE);
+ break;
- (void)libssh2_session_last_error(sshc->ssh_session,
- &err_msg, NULL, 0);
- failf(data, "Failure initializing sftp session: %s", err_msg);
+ case SSH_AUTH_DONE:
+ if(!sshc->authed) {
+ failf(data, "Authentication failure");
state(conn, SSH_SESSION_FREE);
- sshc->actualcode = CURLE_FAILED_INIT;
+ sshc->actualcode = CURLE_LOGIN_DENIED;
break;
}
- }
- state(conn, SSH_SFTP_REALPATH);
- break;
- case SSH_SFTP_REALPATH:
- {
- char tempHome[PATH_MAX];
+ /*
+ * At this point we have an authenticated ssh session.
+ */
+ infof(data, "Authentication complete\n");
+
+ Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSH is connected */
- /*
- * Get the "home" directory
- */
- rc = libssh2_sftp_realpath(sshc->sftp_session, ".",
- tempHome, PATH_MAX-1);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
- }
- else if(rc > 0) {
- /* It seems that this string is not always NULL terminated */
- tempHome[rc] = '\0';
- sshc->homedir = strdup(tempHome);
- if(!sshc->homedir) {
- state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ conn->sockfd = sock;
+ conn->writesockfd = CURL_SOCKET_BAD;
+
+ if(conn->protocol == PROT_SFTP) {
+ state(conn, SSH_SFTP_INIT);
break;
}
- }
- else {
- /* Return the error type */
- err = libssh2_sftp_last_error(sshc->sftp_session);
- result = sftp_libssh2_error_to_CURLE(err);
- sshc->actualcode = result?result:CURLE_SSH;
- DEBUGF(infof(data, "error = %d makes libcurl = %d\n", err, result));
+ infof(data, "SSH CONNECT phase done\n");
state(conn, SSH_STOP);
break;
- }
- }
- /* This is the last step in the SFTP connect phase. Do note that while
- we get the homedir here, we get the "workingpath" in the DO action
- since the homedir will remain the same between request but the
- working path will not. */
- DEBUGF(infof(data, "SSH CONNECT phase done\n"));
- state(conn, SSH_STOP);
- break;
- case SSH_SFTP_QUOTE_INIT:
+ case SSH_SFTP_INIT:
+ /*
+ * Start the libssh2 sftp session
+ */
+ sshc->sftp_session = libssh2_sftp_init(sshc->ssh_session);
+ if(!sshc->sftp_session) {
+ if(libssh2_session_last_errno(sshc->ssh_session) ==
+ LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+ else {
+ char *err_msg;
- result = ssh_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
- if(result) {
- sshc->actualcode = result;
- state(conn, SSH_STOP);
+ (void)libssh2_session_last_error(sshc->ssh_session,
+ &err_msg, NULL, 0);
+ failf(data, "Failure initializing sftp session: %s", err_msg);
+ state(conn, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_FAILED_INIT;
+ break;
+ }
+ }
+ state(conn, SSH_SFTP_REALPATH);
break;
- }
- if(data->set.quote) {
- infof(data, "Sending quote commands\n");
- sshc->quote_item = data->set.quote;
- state(conn, SSH_SFTP_QUOTE);
- }
- else {
- state(conn, SSH_SFTP_TRANS_INIT);
- }
- break;
+ case SSH_SFTP_REALPATH:
+ {
+ char tempHome[PATH_MAX];
- case SSH_SFTP_POSTQUOTE_INIT:
- if(data->set.postquote) {
- infof(data, "Sending quote commands\n");
- sshc->quote_item = data->set.postquote;
- state(conn, SSH_SFTP_QUOTE);
- }
- else {
- state(conn, SSH_STOP);
+ /*
+ * Get the "home" directory
+ */
+ rc = libssh2_sftp_realpath(sshc->sftp_session, ".",
+ tempHome, PATH_MAX-1);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc > 0) {
+ /* It seems that this string is not always NULL terminated */
+ tempHome[rc] = '\0';
+ sshc->homedir = strdup(tempHome);
+ if(!sshc->homedir) {
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ }
+ else {
+ /* Return the error type */
+ err = libssh2_sftp_last_error(sshc->sftp_session);
+ result = sftp_libssh2_error_to_CURLE(err);
+ sshc->actualcode = result?result:CURLE_SSH;
+ DEBUGF(infof(data, "error = %d makes libcurl = %d\n", err, result));
+ state(conn, SSH_STOP);
+ break;
+ }
}
+ /* This is the last step in the SFTP connect phase. Do note that while
+ we get the homedir here, we get the "workingpath" in the DO action
+ since the homedir will remain the same between request but the
+ working path will not. */
+ DEBUGF(infof(data, "SSH CONNECT phase done\n"));
+ state(conn, SSH_STOP);
break;
- case SSH_SFTP_QUOTE:
- /* Send any quote commands */
- {
- const char *cp;
+ case SSH_SFTP_QUOTE_INIT:
- /*
- * Support some of the "FTP" commands
- */
- if(curl_strequal("pwd", sshc->quote_item->data)) {
- /* output debug output if that is requested */
- if(data->set.verbose) {
- char tmp[PATH_MAX+1];
+ result = ssh_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
+ if(result) {
+ sshc->actualcode = result;
+ state(conn, SSH_STOP);
+ break;
+ }
- Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"PWD\n", 4, conn);
- snprintf(tmp, PATH_MAX, "257 \"%s\" is current directory.\n",
- sftp_scp->path);
- Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp), conn);
+ if(data->set.quote) {
+ infof(data, "Sending quote commands\n");
+ sshc->quote_item = data->set.quote;
+ state(conn, SSH_SFTP_QUOTE);
+ }
+ else {
+ state(conn, SSH_SFTP_TRANS_INIT);
}
- state(conn, SSH_SFTP_NEXT_QUOTE);
break;
- }
- else if(sshc->quote_item->data) {
- /*
- * the arguments following the command must be separated from the
- * command with a space so we can check for it unconditionally
- */
- cp = strchr(sshc->quote_item->data, ' ');
- if(cp == NULL) {
- failf(data, "Syntax error in SFTP command. Supply parameter(s)!");
- state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = CURLE_QUOTE_ERROR;
- break;
+
+ case SSH_SFTP_POSTQUOTE_INIT:
+ if(data->set.postquote) {
+ infof(data, "Sending quote commands\n");
+ sshc->quote_item = data->set.postquote;
+ state(conn, SSH_SFTP_QUOTE);
}
+ else {
+ state(conn, SSH_STOP);
+ }
+ break;
+
+ case SSH_SFTP_QUOTE:
+ /* Send any quote commands */
+ {
+ const char *cp;
/*
- * also, every command takes at least one argument so we get that
- * first argument right now
+ * Support some of the "FTP" commands
*/
- result = get_pathname(&cp, &sshc->quote_path1);
- if(result) {
- if(result == CURLE_OUT_OF_MEMORY)
- failf(data, "Out of memory");
- else
- failf(data, "Syntax error: Bad first parameter");
- state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = result;
+ if(curl_strequal("pwd", sshc->quote_item->data)) {
+ /* output debug output if that is requested */
+ if(data->set.verbose) {
+ char tmp[PATH_MAX+1];
+
+ Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"PWD\n", 4, conn);
+ snprintf(tmp, PATH_MAX, "257 \"%s\" is current directory.\n",
+ sftp_scp->path);
+ Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp), conn);
+ }
+ state(conn, SSH_SFTP_NEXT_QUOTE);
break;
}
+ else if(sshc->quote_item->data) {
+ /*
+ * the arguments following the command must be separated from the
+ * command with a space so we can check for it unconditionally
+ */
+ cp = strchr(sshc->quote_item->data, ' ');
+ if(cp == NULL) {
+ failf(data, "Syntax error in SFTP command. Supply parameter(s)!");
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
- /*
- * SFTP is a binary protocol, so we don't send text commands to
- * the server. Instead, we scan for commands for commands used by
- * OpenSSH's sftp program and call the appropriate libssh2
- * functions.
- */
- if(curl_strnequal(sshc->quote_item->data, "chgrp ", 6) ||
- curl_strnequal(sshc->quote_item->data, "chmod ", 6) ||
- curl_strnequal(sshc->quote_item->data, "chown ", 6) ) {
- /* attribute change */
-
- /* sshc->quote_path1 contains the mode to set */
- /* get the destination */
- result = get_pathname(&cp, &sshc->quote_path2);
+ /*
+ * also, every command takes at least one argument so we get that
+ * first argument right now
+ */
+ result = get_pathname(&cp, &sshc->quote_path1);
if(result) {
if(result == CURLE_OUT_OF_MEMORY)
failf(data, "Out of memory");
else
- failf(data, "Syntax error in chgrp/chmod/chown: "
- "Bad second parameter");
- Curl_safefree(sshc->quote_path1);
- sshc->quote_path1 = NULL;
+ failf(data, "Syntax error: Bad first parameter");
state(conn, SSH_SFTP_CLOSE);
sshc->actualcode = result;
break;
}
- memset(&sshc->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
- state(conn, SSH_SFTP_QUOTE_STAT);
+
+ /*
+ * SFTP is a binary protocol, so we don't send text commands to
+ * the server. Instead, we scan for commands for commands used by
+ * OpenSSH's sftp program and call the appropriate libssh2
+ * functions.
+ */
+ if(curl_strnequal(sshc->quote_item->data, "chgrp ", 6) ||
+ curl_strnequal(sshc->quote_item->data, "chmod ", 6) ||
+ curl_strnequal(sshc->quote_item->data, "chown ", 6) ) {
+ /* attribute change */
+
+ /* sshc->quote_path1 contains the mode to set */
+ /* get the destination */
+ result = get_pathname(&cp, &sshc->quote_path2);
+ if(result) {
+ if(result == CURLE_OUT_OF_MEMORY)
+ failf(data, "Out of memory");
+ else
+ failf(data, "Syntax error in chgrp/chmod/chown: "
+ "Bad second parameter");
+ Curl_safefree(sshc->quote_path1);
+ sshc->quote_path1 = NULL;
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = result;
+ break;
+ }
+ memset(&sshc->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
+ state(conn, SSH_SFTP_QUOTE_STAT);
+ break;
+ }
+ else if(curl_strnequal(sshc->quote_item->data, "ln ", 3) ||
+ curl_strnequal(sshc->quote_item->data, "symlink ", 8)) {
+ /* symbolic linking */
+ /* sshc->quote_path1 is the source */
+ /* get the destination */
+ result = get_pathname(&cp, &sshc->quote_path2);
+ if(result) {
+ if(result == CURLE_OUT_OF_MEMORY)
+ failf(data, "Out of memory");
+ else
+ failf(data,
+ "Syntax error in ln/symlink: Bad second parameter");
+ Curl_safefree(sshc->quote_path1);
+ sshc->quote_path1 = NULL;
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = result;
+ break;
+ }
+ state(conn, SSH_SFTP_QUOTE_SYMLINK);
+ break;
+ }
+ else if(curl_strnequal(sshc->quote_item->data, "mkdir ", 6)) {
+ /* create dir */
+ state(conn, SSH_SFTP_QUOTE_MKDIR);
+ break;
+ }
+ else if(curl_strnequal(sshc->quote_item->data, "rename ", 7)) {
+ /* rename file */
+ /* first param is the source path */
+ /* second param is the dest. path */
+ result = get_pathname(&cp, &sshc->quote_path2);
+ if(result) {
+ if(result == CURLE_OUT_OF_MEMORY)
+ failf(data, "Out of memory");
+ else
+ failf(data, "Syntax error in rename: Bad second parameter");
+ Curl_safefree(sshc->quote_path1);
+ sshc->quote_path1 = NULL;
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = result;
+ break;
+ }
+ state(conn, SSH_SFTP_QUOTE_RENAME);
+ break;
+ }
+ else if(curl_strnequal(sshc->quote_item->data, "rmdir ", 6)) {
+ /* delete dir */
+ state(conn, SSH_SFTP_QUOTE_RMDIR);
+ break;
+ }
+ else if(curl_strnequal(sshc->quote_item->data, "rm ", 3)) {
+ state(conn, SSH_SFTP_QUOTE_UNLINK);
+ break;
+ }
+
+ failf(data, "Unknown SFTP command");
+ Curl_safefree(sshc->quote_path1);
+ sshc->quote_path1 = NULL;
+ Curl_safefree(sshc->quote_path2);
+ sshc->quote_path2 = NULL;
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- else if(curl_strnequal(sshc->quote_item->data, "ln ", 3) ||
- curl_strnequal(sshc->quote_item->data, "symlink ", 8)) {
- /* symbolic linking */
- /* sshc->quote_path1 is the source */
- /* get the destination */
- result = get_pathname(&cp, &sshc->quote_path2);
- if(result) {
- if(result == CURLE_OUT_OF_MEMORY)
- failf(data, "Out of memory");
- else
- failf(data,
- "Syntax error in ln/symlink: Bad second parameter");
+ }
+ if(!sshc->quote_item) {
+ state(conn, SSH_SFTP_TRANS_INIT);
+ }
+ break;
+
+ case SSH_SFTP_NEXT_QUOTE:
+ if(sshc->quote_path1) {
+ Curl_safefree(sshc->quote_path1);
+ sshc->quote_path1 = NULL;
+ }
+ if(sshc->quote_path2) {
+ Curl_safefree(sshc->quote_path2);
+ sshc->quote_path2 = NULL;
+ }
+
+ sshc->quote_item = sshc->quote_item->next;
+
+ if(sshc->quote_item) {
+ state(conn, SSH_SFTP_QUOTE);
+ }
+ else {
+ if(sshc->nextstate != SSH_NO_STATE) {
+ state(conn, sshc->nextstate);
+ sshc->nextstate = SSH_NO_STATE;
+ }
+ else {
+ state(conn, SSH_SFTP_TRANS_INIT);
+ }
+ }
+ break;
+
+ case SSH_SFTP_QUOTE_STAT:
+ if(!curl_strnequal(sshc->quote_item->data, "chmod", 5)) {
+ /* Since chown and chgrp only set owner OR group but libssh2 wants to
+ * set them both at once, we need to obtain the current ownership first.
+ * This takes an extra protocol round trip.
+ */
+ rc = libssh2_sftp_stat(sshc->sftp_session, sshc->quote_path2,
+ &sshc->quote_attrs);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc != 0) { /* get those attributes */
+ err = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
sshc->quote_path1 = NULL;
+ Curl_safefree(sshc->quote_path2);
+ sshc->quote_path2 = NULL;
+ failf(data, "Attempt to get SFTP stats failed: %s",
+ sftp_libssh2_strerror(err));
state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = result;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- state(conn, SSH_SFTP_QUOTE_SYMLINK);
- break;
- }
- else if(curl_strnequal(sshc->quote_item->data, "mkdir ", 6)) {
- /* create dir */
- state(conn, SSH_SFTP_QUOTE_MKDIR);
- break;
}
- else if(curl_strnequal(sshc->quote_item->data, "rename ", 7)) {
- /* rename file */
- /* first param is the source path */
- /* second param is the dest. path */
- result = get_pathname(&cp, &sshc->quote_path2);
- if(result) {
- if(result == CURLE_OUT_OF_MEMORY)
- failf(data, "Out of memory");
- else
- failf(data, "Syntax error in rename: Bad second parameter");
+
+ /* Now set the new attributes... */
+ if(curl_strnequal(sshc->quote_item->data, "chgrp", 5)) {
+ sshc->quote_attrs.gid = strtol(sshc->quote_path1, NULL, 10);
+ sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
+ if(sshc->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0])) {
Curl_safefree(sshc->quote_path1);
sshc->quote_path1 = NULL;
+ Curl_safefree(sshc->quote_path2);
+ sshc->quote_path2 = NULL;
+ failf(data, "Syntax error: chgrp gid not a number");
state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = result;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- state(conn, SSH_SFTP_QUOTE_RENAME);
- break;
}
- else if(curl_strnequal(sshc->quote_item->data, "rmdir ", 6)) {
- /* delete dir */
- state(conn, SSH_SFTP_QUOTE_RMDIR);
- break;
+ else if(curl_strnequal(sshc->quote_item->data, "chmod", 5)) {
+ sshc->quote_attrs.permissions = strtol(sshc->quote_path1, NULL, 8);
+ sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS;
+ /* permissions are octal */
+ if(sshc->quote_attrs.permissions == 0 &&
+ !ISDIGIT(sshc->quote_path1[0])) {
+ Curl_safefree(sshc->quote_path1);
+ sshc->quote_path1 = NULL;
+ Curl_safefree(sshc->quote_path2);
+ sshc->quote_path2 = NULL;
+ failf(data, "Syntax error: chmod permissions not a number");
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
}
- else if(curl_strnequal(sshc->quote_item->data, "rm ", 3)) {
- state(conn, SSH_SFTP_QUOTE_UNLINK);
- break;
+ else if(curl_strnequal(sshc->quote_item->data, "chown", 5)) {
+ sshc->quote_attrs.uid = strtol(sshc->quote_path1, NULL, 10);
+ sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
+ if(sshc->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0])) {
+ Curl_safefree(sshc->quote_path1);
+ sshc->quote_path1 = NULL;
+ Curl_safefree(sshc->quote_path2);
+ sshc->quote_path2 = NULL;
+ failf(data, "Syntax error: chown uid not a number");
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
}
- failf(data, "Unknown SFTP command");
- Curl_safefree(sshc->quote_path1);
- sshc->quote_path1 = NULL;
- Curl_safefree(sshc->quote_path2);
- sshc->quote_path2 = NULL;
- state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = CURLE_QUOTE_ERROR;
+ /* Now send the completed structure... */
+ state(conn, SSH_SFTP_QUOTE_SETSTAT);
break;
- }
- }
- if(!sshc->quote_item) {
- state(conn, SSH_SFTP_TRANS_INIT);
- }
- break;
-
- case SSH_SFTP_NEXT_QUOTE:
- if(sshc->quote_path1) {
- Curl_safefree(sshc->quote_path1);
- sshc->quote_path1 = NULL;
- }
- if(sshc->quote_path2) {
- Curl_safefree(sshc->quote_path2);
- sshc->quote_path2 = NULL;
- }
- sshc->quote_item = sshc->quote_item->next;
-
- if(sshc->quote_item) {
- state(conn, SSH_SFTP_QUOTE);
- }
- else {
- if(sshc->nextstate != SSH_NO_STATE) {
- state(conn, sshc->nextstate);
- sshc->nextstate = SSH_NO_STATE;
- }
- else {
- state(conn, SSH_SFTP_TRANS_INIT);
- }
- }
- break;
-
- case SSH_SFTP_QUOTE_STAT:
- if(!curl_strnequal(sshc->quote_item->data, "chmod", 5)) {
- /* Since chown and chgrp only set owner OR group but libssh2 wants to
- * set them both at once, we need to obtain the current ownership first.
- * This takes an extra protocol round trip.
- */
- rc = libssh2_sftp_stat(sshc->sftp_session, sshc->quote_path2,
- &sshc->quote_attrs);
+ case SSH_SFTP_QUOTE_SETSTAT:
+ rc = libssh2_sftp_setstat(sshc->sftp_session, sshc->quote_path2,
+ &sshc->quote_attrs);
if(rc == LIBSSH2_ERROR_EAGAIN) {
break;
}
- else if(rc != 0) { /* get those attributes */
+ else if(rc != 0) {
err = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
sshc->quote_path1 = NULL;
Curl_safefree(sshc->quote_path2);
sshc->quote_path2 = NULL;
- failf(data, "Attempt to get SFTP stats failed: %s",
+ failf(data, "Attempt to set SFTP stats failed: %s",
sftp_libssh2_strerror(err));
state(conn, SSH_SFTP_CLOSE);
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- }
+ state(conn, SSH_SFTP_NEXT_QUOTE);
+ break;
- /* Now set the new attributes... */
- if(curl_strnequal(sshc->quote_item->data, "chgrp", 5)) {
- sshc->quote_attrs.gid = strtol(sshc->quote_path1, NULL, 10);
- sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
- if(sshc->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0])) {
+ case SSH_SFTP_QUOTE_SYMLINK:
+ rc = libssh2_sftp_symlink(sshc->sftp_session, sshc->quote_path1,
+ sshc->quote_path2);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc != 0) {
+ err = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
sshc->quote_path1 = NULL;
Curl_safefree(sshc->quote_path2);
sshc->quote_path2 = NULL;
- failf(data, "Syntax error: chgrp gid not a number");
+ failf(data, "symlink command failed: %s",
+ sftp_libssh2_strerror(err));
state(conn, SSH_SFTP_CLOSE);
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- }
- else if(curl_strnequal(sshc->quote_item->data, "chmod", 5)) {
- sshc->quote_attrs.permissions = strtol(sshc->quote_path1, NULL, 8);
- sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS;
- /* permissions are octal */
- if(sshc->quote_attrs.permissions == 0 &&
- !ISDIGIT(sshc->quote_path1[0])) {
+ state(conn, SSH_SFTP_NEXT_QUOTE);
+ break;
+
+ case SSH_SFTP_QUOTE_MKDIR:
+ rc = libssh2_sftp_mkdir(sshc->sftp_session, sshc->quote_path1, 0755);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc != 0) {
+ err = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
sshc->quote_path1 = NULL;
- Curl_safefree(sshc->quote_path2);
- sshc->quote_path2 = NULL;
- failf(data, "Syntax error: chmod permissions not a number");
+ failf(data, "mkdir command failed: %s", sftp_libssh2_strerror(err));
state(conn, SSH_SFTP_CLOSE);
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- }
- else if(curl_strnequal(sshc->quote_item->data, "chown", 5)) {
- sshc->quote_attrs.uid = strtol(sshc->quote_path1, NULL, 10);
- sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
- if(sshc->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0])) {
+ state(conn, SSH_SFTP_NEXT_QUOTE);
+ break;
+
+ case SSH_SFTP_QUOTE_RENAME:
+ rc = libssh2_sftp_rename(sshc->sftp_session, sshc->quote_path1,
+ sshc->quote_path2);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc != 0) {
+ err = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
sshc->quote_path1 = NULL;
Curl_safefree(sshc->quote_path2);
sshc->quote_path2 = NULL;
- failf(data, "Syntax error: chown uid not a number");
+ failf(data, "rename command failed: %s", sftp_libssh2_strerror(err));
state(conn, SSH_SFTP_CLOSE);
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- }
-
- /* Now send the completed structure... */
- state(conn, SSH_SFTP_QUOTE_SETSTAT);
- break;
-
- case SSH_SFTP_QUOTE_SETSTAT:
- rc = libssh2_sftp_setstat(sshc->sftp_session, sshc->quote_path2,
- &sshc->quote_attrs);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
- }
- else if(rc != 0) {
- err = libssh2_sftp_last_error(sshc->sftp_session);
- Curl_safefree(sshc->quote_path1);
- sshc->quote_path1 = NULL;
- Curl_safefree(sshc->quote_path2);
- sshc->quote_path2 = NULL;
- failf(data, "Attempt to set SFTP stats failed: %s",
- sftp_libssh2_strerror(err));
- state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = CURLE_QUOTE_ERROR;
- break;
- }
- state(conn, SSH_SFTP_NEXT_QUOTE);
- break;
-
- case SSH_SFTP_QUOTE_SYMLINK:
- rc = libssh2_sftp_symlink(sshc->sftp_session, sshc->quote_path1,
- sshc->quote_path2);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
- }
- else if(rc != 0) {
- err = libssh2_sftp_last_error(sshc->sftp_session);
- Curl_safefree(sshc->quote_path1);
- sshc->quote_path1 = NULL;
- Curl_safefree(sshc->quote_path2);
- sshc->quote_path2 = NULL;
- failf(data, "symlink command failed: %s",
- sftp_libssh2_strerror(err));
- state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = CURLE_QUOTE_ERROR;
- break;
- }
- state(conn, SSH_SFTP_NEXT_QUOTE);
- break;
-
- case SSH_SFTP_QUOTE_MKDIR:
- rc = libssh2_sftp_mkdir(sshc->sftp_session, sshc->quote_path1, 0755);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
- }
- else if(rc != 0) {
- err = libssh2_sftp_last_error(sshc->sftp_session);
- Curl_safefree(sshc->quote_path1);
- sshc->quote_path1 = NULL;
- failf(data, "mkdir command failed: %s", sftp_libssh2_strerror(err));
- state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = CURLE_QUOTE_ERROR;
+ state(conn, SSH_SFTP_NEXT_QUOTE);
break;
- }
- state(conn, SSH_SFTP_NEXT_QUOTE);
- break;
- case SSH_SFTP_QUOTE_RENAME:
- rc = libssh2_sftp_rename(sshc->sftp_session, sshc->quote_path1,
- sshc->quote_path2);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
- }
- else if(rc != 0) {
- err = libssh2_sftp_last_error(sshc->sftp_session);
- Curl_safefree(sshc->quote_path1);
- sshc->quote_path1 = NULL;
- Curl_safefree(sshc->quote_path2);
- sshc->quote_path2 = NULL;
- failf(data, "rename command failed: %s", sftp_libssh2_strerror(err));
- state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = CURLE_QUOTE_ERROR;
+ case SSH_SFTP_QUOTE_RMDIR:
+ rc = libssh2_sftp_rmdir(sshc->sftp_session, sshc->quote_path1);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc != 0) {
+ err = libssh2_sftp_last_error(sshc->sftp_session);
+ Curl_safefree(sshc->quote_path1);
+ sshc->quote_path1 = NULL;
+ failf(data, "rmdir command failed: %s", sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ state(conn, SSH_SFTP_NEXT_QUOTE);
break;
- }
- state(conn, SSH_SFTP_NEXT_QUOTE);
- break;
- case SSH_SFTP_QUOTE_RMDIR:
- rc = libssh2_sftp_rmdir(sshc->sftp_session, sshc->quote_path1);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
- }
- else if(rc != 0) {
- err = libssh2_sftp_last_error(sshc->sftp_session);
- Curl_safefree(sshc->quote_path1);
- sshc->quote_path1 = NULL;
- failf(data, "rmdir command failed: %s", sftp_libssh2_strerror(err));
- state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = CURLE_QUOTE_ERROR;
+ case SSH_SFTP_QUOTE_UNLINK:
+ rc = libssh2_sftp_unlink(sshc->sftp_session, sshc->quote_path1);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc != 0) {
+ err = libssh2_sftp_last_error(sshc->sftp_session);
+ Curl_safefree(sshc->quote_path1);
+ sshc->quote_path1 = NULL;
+ failf(data, "rm command failed: %s", sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ state(conn, SSH_SFTP_NEXT_QUOTE);
break;
- }
- state(conn, SSH_SFTP_NEXT_QUOTE);
- break;
- case SSH_SFTP_QUOTE_UNLINK:
- rc = libssh2_sftp_unlink(sshc->sftp_session, sshc->quote_path1);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
- }
- else if(rc != 0) {
- err = libssh2_sftp_last_error(sshc->sftp_session);
- Curl_safefree(sshc->quote_path1);
- sshc->quote_path1 = NULL;
- failf(data, "rm command failed: %s", sftp_libssh2_strerror(err));
- state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = CURLE_QUOTE_ERROR;
+ case SSH_SFTP_TRANS_INIT:
+ if(data->set.upload)
+ state(conn, SSH_SFTP_UPLOAD_INIT);
+ else {
+ if(data->set.opt_no_body)
+ state(conn, SSH_STOP);
+ else if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/')
+ state(conn, SSH_SFTP_READDIR_INIT);
+ else
+ state(conn, SSH_SFTP_DOWNLOAD_INIT);
+ }
break;
- }
- state(conn, SSH_SFTP_NEXT_QUOTE);
- break;
- case SSH_SFTP_TRANS_INIT:
- if(data->set.upload)
- state(conn, SSH_SFTP_UPLOAD_INIT);
- else {
- if(data->set.opt_no_body)
- state(conn, SSH_STOP);
- else if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/')
- state(conn, SSH_SFTP_READDIR_INIT);
- else
- state(conn, SSH_SFTP_DOWNLOAD_INIT);
- }
- break;
+ case SSH_SFTP_UPLOAD_INIT:
+ {
+ unsigned long flags;
+ /*
+ * NOTE!!! libssh2 requires that the destination path is a full path
+ * that includes the destination file and name OR ends in a "/"
+ * If this is not done the destination file will be named the
+ * same name as the last directory in the path.
+ */
- case SSH_SFTP_UPLOAD_INIT:
- {
- unsigned long flags;
- /*
- * NOTE!!! libssh2 requires that the destination path is a full path
- * that includes the destination file and name OR ends in a "/"
- * If this is not done the destination file will be named the
- * same name as the last directory in the path.
- */
-
- if(data->state.resume_from != 0) {
- LIBSSH2_SFTP_ATTRIBUTES attrs;
- if(data->state.resume_from< 0) {
- rc = libssh2_sftp_stat(sshc->sftp_session, sftp_scp->path, &attrs);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
- }
- else if(rc) {
- data->state.resume_from = 0;
- }
- else {
- data->state.resume_from = attrs.filesize;
+ if(data->state.resume_from != 0) {
+ LIBSSH2_SFTP_ATTRIBUTES attrs;
+ if(data->state.resume_from< 0) {
+ rc = libssh2_sftp_stat(sshc->sftp_session, sftp_scp->path, &attrs);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc) {
+ data->state.resume_from = 0;
+ }
+ else {
+ data->state.resume_from = attrs.filesize;
+ }
}
}
- }
- if(data->set.ftp_append)
- /* Try to open for append, but create if nonexisting */
- flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_APPEND;
- else if (data->state.resume_from > 0)
- /* If we have restart position then open for append */
- flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_APPEND;
- else
- /* Clear file before writing (normal behaviour) */
- flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC;
+ if(data->set.ftp_append)
+ /* Try to open for append, but create if nonexisting */
+ flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_APPEND;
+ else if (data->state.resume_from > 0)
+ /* If we have restart position then open for append */
+ flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_APPEND;
+ else
+ /* Clear file before writing (normal behaviour) */
+ flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC;
- sshc->sftp_handle =
- libssh2_sftp_open(sshc->sftp_session, sftp_scp->path,
- flags, data->set.new_file_perms);
+ sshc->sftp_handle =
+ libssh2_sftp_open(sshc->sftp_session, sftp_scp->path,
+ flags, data->set.new_file_perms);
- if(!sshc->sftp_handle) {
- rc = libssh2_session_last_errno(sshc->ssh_session);
+ if(!sshc->sftp_handle) {
+ rc = libssh2_session_last_errno(sshc->ssh_session);
- if(LIBSSH2_ERROR_EAGAIN == rc)
- break;
- else {
- if(LIBSSH2_ERROR_SFTP_PROTOCOL == rc)
- /* only when there was an SFTP protocol error can we extract
- the sftp error! */
- err = libssh2_sftp_last_error(sshc->sftp_session);
- else
- err = -1; /* not an sftp error at all */
+ if(LIBSSH2_ERROR_EAGAIN == rc)
+ break;
+ else {
+ if(LIBSSH2_ERROR_SFTP_PROTOCOL == rc)
+ /* only when there was an SFTP protocol error can we extract
+ the sftp error! */
+ err = libssh2_sftp_last_error(sshc->sftp_session);
+ else
+ err = -1; /* not an sftp error at all */
- if(sshc->secondCreateDirs) {
+ if(sshc->secondCreateDirs) {
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = err>= LIBSSH2_FX_OK?
+ sftp_libssh2_error_to_CURLE(err):CURLE_SSH;
+ failf(data, "Creating the dir/file failed: %s",
+ sftp_libssh2_strerror(err));
+ break;
+ }
+ else if(((err == LIBSSH2_FX_NO_SUCH_FILE) ||
+ (err == LIBSSH2_FX_FAILURE) ||
+ (err == LIBSSH2_FX_NO_SUCH_PATH)) &&
+ (data->set.ftp_create_missing_dirs &&
+ (strlen(sftp_scp->path) > 1))) {
+ /* try to create the path remotely */
+ sshc->secondCreateDirs = 1;
+ state(conn, SSH_SFTP_CREATE_DIRS_INIT);
+ break;
+ }
state(conn, SSH_SFTP_CLOSE);
sshc->actualcode = err>= LIBSSH2_FX_OK?
sftp_libssh2_error_to_CURLE(err):CURLE_SSH;
- failf(data, "Creating the dir/file failed: %s",
- sftp_libssh2_strerror(err));
- break;
- }
- else if(((err == LIBSSH2_FX_NO_SUCH_FILE) ||
- (err == LIBSSH2_FX_FAILURE) ||
- (err == LIBSSH2_FX_NO_SUCH_PATH)) &&
- (data->set.ftp_create_missing_dirs &&
- (strlen(sftp_scp->path) > 1))) {
- /* try to create the path remotely */
- sshc->secondCreateDirs = 1;
- state(conn, SSH_SFTP_CREATE_DIRS_INIT);
+ if(!sshc->actualcode) {
+ /* Sometimes, for some reason libssh2_sftp_last_error() returns
+ zero even though libssh2_sftp_open() failed previously! We need
+ to work around that! */
+ sshc->actualcode = CURLE_SSH;
+ err=-1;
+ }
+ failf(data, "Upload failed: %s (%d/%d)",
+ err>= LIBSSH2_FX_OK?sftp_libssh2_strerror(err):"ssh error",
+ err, rc);
break;
}
- state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = err>= LIBSSH2_FX_OK?
- sftp_libssh2_error_to_CURLE(err):CURLE_SSH;
- if(!sshc->actualcode) {
- /* Sometimes, for some reason libssh2_sftp_last_error() returns zero
- even though libssh2_sftp_open() failed previously! We need to
- work around that! */
- sshc->actualcode = CURLE_SSH;
- err=-1;
- }
- failf(data, "Upload failed: %s (%d/%d)",
- err>= LIBSSH2_FX_OK?sftp_libssh2_strerror(err):"ssh error",
- err, rc);
- break;
}
- }
- /* If we have 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(conn->seek_func) {
- seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
- SEEK_SET);
- }
+ /* If we have 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(conn->seek_func) {
+ seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
+ SEEK_SET);
+ }
- if(seekerr != CURL_SEEKFUNC_OK){
+ if(seekerr != CURL_SEEKFUNC_OK){
- if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
- failf(data, "Could not seek stream");
- return CURLE_FTP_COULDNT_USE_REST;
+ if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
+ failf(data, "Could not seek stream");
+ return CURLE_FTP_COULDNT_USE_REST;
+ }
+ /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
+ else {
+ curl_off_t passed=0;
+ curl_off_t readthisamountnow;
+ curl_off_t actuallyread;
+ do {
+ readthisamountnow = (data->state.resume_from - passed);
+
+ if(readthisamountnow > BUFSIZE)
+ readthisamountnow = BUFSIZE;
+
+ actuallyread =
+ (curl_off_t) conn->fread_func(data->state.buffer, 1,
+ (size_t)readthisamountnow,
+ conn->fread_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");
+ return CURLE_FTP_COULDNT_USE_REST;
+ }
+ } while(passed < data->state.resume_from);
+ }
}
- /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
- else {
- curl_off_t passed=0;
- curl_off_t readthisamountnow;
- curl_off_t actuallyread;
- do {
- readthisamountnow = (data->state.resume_from - passed);
-
- if(readthisamountnow > BUFSIZE)
- readthisamountnow = BUFSIZE;
-
- actuallyread =
- (curl_off_t) conn->fread_func(data->state.buffer, 1,
- (size_t)readthisamountnow,
- conn->fread_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");
- return CURLE_FTP_COULDNT_USE_REST;
- }
- } while(passed < data->state.resume_from);
+
+ /* now, decrease the size of the read */
+ if(data->set.infilesize>0) {
+ data->set.infilesize -= data->state.resume_from;
+ data->req.size = data->set.infilesize;
+ Curl_pgrsSetUploadSize(data, data->set.infilesize);
}
- }
- /* now, decrease the size of the read */
+ SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
+ }
if(data->set.infilesize>0) {
- data->set.infilesize -= data->state.resume_from;
data->req.size = data->set.infilesize;
Curl_pgrsSetUploadSize(data, data->set.infilesize);
}
+ /* upload data */
+ result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL,
+ FIRSTSOCKET, NULL);
- SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
- }
- if(data->set.infilesize>0) {
- data->req.size = data->set.infilesize;
- Curl_pgrsSetUploadSize(data, data->set.infilesize);
- }
- /* upload data */
- result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL,
- FIRSTSOCKET, NULL);
-
- /* not set by Curl_setup_transfer to preserve keepon bits */
- conn->sockfd = conn->writesockfd;
-
- if(result) {
- state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = result;
- }
- else {
- /* store this original bitmask setup to use later on if we can't figure
- out a "real" bitmask */
- sshc->orig_waitfor = data->req.keepon;
-
- state(conn, SSH_STOP);
- }
- break;
- }
-
- case SSH_SFTP_CREATE_DIRS_INIT:
- if(strlen(sftp_scp->path) > 1) {
- sshc->slash_pos = sftp_scp->path + 1; /* ignore the leading '/' */
- state(conn, SSH_SFTP_CREATE_DIRS);
- }
- else {
- state(conn, SSH_SFTP_UPLOAD_INIT);
- }
- break;
+ /* not set by Curl_setup_transfer to preserve keepon bits */
+ conn->sockfd = conn->writesockfd;
- case SSH_SFTP_CREATE_DIRS:
- if((sshc->slash_pos = strchr(sshc->slash_pos, '/')) != NULL) {
- *sshc->slash_pos = 0;
+ if(result) {
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = result;
+ }
+ else {
+ /* store this original bitmask setup to use later on if we can't
+ figure out a "real" bitmask */
+ sshc->orig_waitfor = data->req.keepon;
- infof(data, "Creating directory '%s'\n", sftp_scp->path);
- state(conn, SSH_SFTP_CREATE_DIRS_MKDIR);
+ state(conn, SSH_STOP);
+ }
break;
}
- else {
- state(conn, SSH_SFTP_UPLOAD_INIT);
- }
- break;
- case SSH_SFTP_CREATE_DIRS_MKDIR:
- /* 'mode' - parameter is preliminary - default to 0644 */
- rc = libssh2_sftp_mkdir(sshc->sftp_session, sftp_scp->path,
- data->set.new_directory_perms);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
- }
- *sshc->slash_pos = '/';
- ++sshc->slash_pos;
- if(rc == -1) {
- unsigned int sftp_err = 0;
- /*
- * abort if failure wasn't that the dir already exists or the
- * permission was denied (creation might succeed further
- * down the path) - retry on unspecific FAILURE also
- */
- sftp_err = libssh2_sftp_last_error(sshc->sftp_session);
- if((sftp_err != LIBSSH2_FX_FILE_ALREADY_EXISTS) &&
- (sftp_err != LIBSSH2_FX_FAILURE) &&
- (sftp_err != LIBSSH2_FX_PERMISSION_DENIED)) {
- result = sftp_libssh2_error_to_CURLE(sftp_err);
- state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = result?result:CURLE_SSH;
- break;
+ case SSH_SFTP_CREATE_DIRS_INIT:
+ if(strlen(sftp_scp->path) > 1) {
+ sshc->slash_pos = sftp_scp->path + 1; /* ignore the leading '/' */
+ state(conn, SSH_SFTP_CREATE_DIRS);
}
- }
- state(conn, SSH_SFTP_CREATE_DIRS);
- break;
+ else {
+ state(conn, SSH_SFTP_UPLOAD_INIT);
+ }
+ break;
- case SSH_SFTP_READDIR_INIT:
- /*
- * This is a directory that we are trying to get, so produce a
- * directory listing
- */
- sshc->sftp_handle = libssh2_sftp_opendir(sshc->sftp_session,
- sftp_scp->path);
- if(!sshc->sftp_handle) {
- if(libssh2_session_last_errno(sshc->ssh_session) ==
- LIBSSH2_ERROR_EAGAIN) {
- rc = LIBSSH2_ERROR_EAGAIN;
+ case SSH_SFTP_CREATE_DIRS:
+ if((sshc->slash_pos = strchr(sshc->slash_pos, '/')) != NULL) {
+ *sshc->slash_pos = 0;
+
+ infof(data, "Creating directory '%s'\n", sftp_scp->path);
+ state(conn, SSH_SFTP_CREATE_DIRS_MKDIR);
break;
}
else {
- err = libssh2_sftp_last_error(sshc->sftp_session);
- failf(data, "Could not open directory for reading: %s",
- sftp_libssh2_strerror(err));
- state(conn, SSH_SFTP_CLOSE);
- result = sftp_libssh2_error_to_CURLE(err);
- sshc->actualcode = result?result:CURLE_SSH;
- break;
+ state(conn, SSH_SFTP_UPLOAD_INIT);
}
- }
- if((sshc->readdir_filename = malloc(PATH_MAX+1)) == NULL) {
- state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = CURLE_OUT_OF_MEMORY;
- break;
- }
- if((sshc->readdir_longentry = malloc(PATH_MAX+1)) == NULL) {
- Curl_safefree(sshc->readdir_filename);
- sshc->readdir_filename = NULL;
- state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = CURLE_OUT_OF_MEMORY;
- break;
- }
- state(conn, SSH_SFTP_READDIR);
- break;
-
- case SSH_SFTP_READDIR:
- sshc->readdir_len = libssh2_sftp_readdir_ex(sshc->sftp_handle,
- sshc->readdir_filename,
- PATH_MAX,
- sshc->readdir_longentry,
- PATH_MAX,
- &sshc->readdir_attrs);
- if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) {
- rc = LIBSSH2_ERROR_EAGAIN;
break;
- }
- if(sshc->readdir_len > 0) {
- sshc->readdir_filename[sshc->readdir_len] = '\0';
-
- if(data->set.ftp_list_only) {
- char *tmpLine;
- tmpLine = aprintf("%s\n", sshc->readdir_filename);
- if(tmpLine == NULL) {
+ case SSH_SFTP_CREATE_DIRS_MKDIR:
+ /* 'mode' - parameter is preliminary - default to 0644 */
+ rc = libssh2_sftp_mkdir(sshc->sftp_session, sftp_scp->path,
+ data->set.new_directory_perms);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ *sshc->slash_pos = '/';
+ ++sshc->slash_pos;
+ if(rc == -1) {
+ unsigned int sftp_err = 0;
+ /*
+ * Abort if failure wasn't that the dir already exists or the
+ * permission was denied (creation might succeed further down the
+ * path) - retry on unspecific FAILURE also
+ */
+ sftp_err = libssh2_sftp_last_error(sshc->sftp_session);
+ if((sftp_err != LIBSSH2_FX_FILE_ALREADY_EXISTS) &&
+ (sftp_err != LIBSSH2_FX_FAILURE) &&
+ (sftp_err != LIBSSH2_FX_PERMISSION_DENIED)) {
+ result = sftp_libssh2_error_to_CURLE(sftp_err);
state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ sshc->actualcode = result?result:CURLE_SSH;
break;
}
- result = Curl_client_write(conn, CLIENTWRITE_BODY,
- tmpLine, sshc->readdir_len+1);
- Curl_safefree(tmpLine);
+ }
+ state(conn, SSH_SFTP_CREATE_DIRS);
+ break;
- if(result) {
- state(conn, SSH_STOP);
+ case SSH_SFTP_READDIR_INIT:
+ /*
+ * This is a directory that we are trying to get, so produce a directory
+ * listing
+ */
+ sshc->sftp_handle = libssh2_sftp_opendir(sshc->sftp_session,
+ sftp_scp->path);
+ if(!sshc->sftp_handle) {
+ if(libssh2_session_last_errno(sshc->ssh_session) ==
+ LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
break;
}
- /* since this counts what we send to the client, we include the newline
- in this counter */
- data->req.bytecount += sshc->readdir_len+1;
-
- /* output debug output if that is requested */
- if(data->set.verbose) {
- Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_filename,
- sshc->readdir_len, conn);
- }
- }
- else {
- sshc->readdir_currLen = strlen(sshc->readdir_longentry);
- sshc->readdir_totalLen = 80 + sshc->readdir_currLen;
- sshc->readdir_line = calloc(sshc->readdir_totalLen, 1);
- if(!sshc->readdir_line) {
- Curl_safefree(sshc->readdir_filename);
- sshc->readdir_filename = NULL;
- Curl_safefree(sshc->readdir_longentry);
- sshc->readdir_longentry = NULL;
+ else {
+ err = libssh2_sftp_last_error(sshc->sftp_session);
+ failf(data, "Could not open directory for reading: %s",
+ sftp_libssh2_strerror(err));
state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ result = sftp_libssh2_error_to_CURLE(err);
+ sshc->actualcode = result?result:CURLE_SSH;
break;
}
+ }
+ if((sshc->readdir_filename = malloc(PATH_MAX+1)) == NULL) {
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ if((sshc->readdir_longentry = malloc(PATH_MAX+1)) == NULL) {
+ Curl_safefree(sshc->readdir_filename);
+ sshc->readdir_filename = NULL;
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ state(conn, SSH_SFTP_READDIR);
+ break;
+
+ case SSH_SFTP_READDIR:
+ sshc->readdir_len = libssh2_sftp_readdir_ex(sshc->sftp_handle,
+ sshc->readdir_filename,
+ PATH_MAX,
+ sshc->readdir_longentry,
+ PATH_MAX,
+ &sshc->readdir_attrs);
+ if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+ if(sshc->readdir_len > 0) {
+ sshc->readdir_filename[sshc->readdir_len] = '\0';
+
+ if(data->set.ftp_list_only) {
+ char *tmpLine;
- memcpy(sshc->readdir_line, sshc->readdir_longentry,
- sshc->readdir_currLen);
- if((sshc->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
- ((sshc->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
- LIBSSH2_SFTP_S_IFLNK)) {
- sshc->readdir_linkPath = malloc(PATH_MAX + 1);
- if(sshc->readdir_linkPath == NULL) {
+ tmpLine = aprintf("%s\n", sshc->readdir_filename);
+ if(tmpLine == NULL) {
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ result = Curl_client_write(conn, CLIENTWRITE_BODY,
+ tmpLine, sshc->readdir_len+1);
+ Curl_safefree(tmpLine);
+
+ if(result) {
+ state(conn, SSH_STOP);
+ break;
+ }
+ /* since this counts what we send to the client, we include the
+ newline in this counter */
+ data->req.bytecount += sshc->readdir_len+1;
+
+ /* output debug output if that is requested */
+ if(data->set.verbose) {
+ Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_filename,
+ sshc->readdir_len, conn);
+ }
+ }
+ else {
+ sshc->readdir_currLen = strlen(sshc->readdir_longentry);
+ sshc->readdir_totalLen = 80 + sshc->readdir_currLen;
+ sshc->readdir_line = calloc(sshc->readdir_totalLen, 1);
+ if(!sshc->readdir_line) {
Curl_safefree(sshc->readdir_filename);
sshc->readdir_filename = NULL;
Curl_safefree(sshc->readdir_longentry);
@@ -1678,563 +1665,581 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
break;
}
- snprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", sftp_scp->path,
- sshc->readdir_filename);
- state(conn, SSH_SFTP_READDIR_LINK);
+ memcpy(sshc->readdir_line, sshc->readdir_longentry,
+ sshc->readdir_currLen);
+ if((sshc->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
+ ((sshc->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
+ LIBSSH2_SFTP_S_IFLNK)) {
+ sshc->readdir_linkPath = malloc(PATH_MAX + 1);
+ if(sshc->readdir_linkPath == NULL) {
+ Curl_safefree(sshc->readdir_filename);
+ sshc->readdir_filename = NULL;
+ Curl_safefree(sshc->readdir_longentry);
+ sshc->readdir_longentry = NULL;
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+
+ snprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", sftp_scp->path,
+ sshc->readdir_filename);
+ state(conn, SSH_SFTP_READDIR_LINK);
+ break;
+ }
+ state(conn, SSH_SFTP_READDIR_BOTTOM);
break;
}
- state(conn, SSH_SFTP_READDIR_BOTTOM);
+ }
+ else if(sshc->readdir_len == 0) {
+ Curl_safefree(sshc->readdir_filename);
+ sshc->readdir_filename = NULL;
+ Curl_safefree(sshc->readdir_longentry);
+ sshc->readdir_longentry = NULL;
+ state(conn, SSH_SFTP_READDIR_DONE);
+ break;
+ }
+ else if(sshc->readdir_len <= 0) {
+ err = libssh2_sftp_last_error(sshc->sftp_session);
+ result = sftp_libssh2_error_to_CURLE(err);
+ sshc->actualcode = result?result:CURLE_SSH;
+ failf(data, "Could not open remote file for reading: %s :: %d",
+ sftp_libssh2_strerror(err),
+ libssh2_session_last_errno(sshc->ssh_session));
+ Curl_safefree(sshc->readdir_filename);
+ sshc->readdir_filename = NULL;
+ Curl_safefree(sshc->readdir_longentry);
+ sshc->readdir_longentry = NULL;
+ state(conn, SSH_SFTP_CLOSE);
break;
}
- }
- else if(sshc->readdir_len == 0) {
- Curl_safefree(sshc->readdir_filename);
- sshc->readdir_filename = NULL;
- Curl_safefree(sshc->readdir_longentry);
- sshc->readdir_longentry = NULL;
- state(conn, SSH_SFTP_READDIR_DONE);
- break;
- }
- else if(sshc->readdir_len <= 0) {
- err = libssh2_sftp_last_error(sshc->sftp_session);
- result = sftp_libssh2_error_to_CURLE(err);
- sshc->actualcode = result?result:CURLE_SSH;
- failf(data, "Could not open remote file for reading: %s :: %d",
- sftp_libssh2_strerror(err),
- libssh2_session_last_errno(sshc->ssh_session));
- Curl_safefree(sshc->readdir_filename);
- sshc->readdir_filename = NULL;
- Curl_safefree(sshc->readdir_longentry);
- sshc->readdir_longentry = NULL;
- state(conn, SSH_SFTP_CLOSE);
break;
- }
- break;
- case SSH_SFTP_READDIR_LINK:
- sshc->readdir_len = libssh2_sftp_readlink(sshc->sftp_session,
- sshc->readdir_linkPath,
- sshc->readdir_filename,
- PATH_MAX);
- if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) {
- rc = LIBSSH2_ERROR_EAGAIN;
- break;
- }
- Curl_safefree(sshc->readdir_linkPath);
- sshc->readdir_linkPath = NULL;
- sshc->readdir_line = realloc(sshc->readdir_line,
- sshc->readdir_totalLen + 4 +
- sshc->readdir_len);
- if(!sshc->readdir_line) {
- Curl_safefree(sshc->readdir_filename);
- sshc->readdir_filename = NULL;
- Curl_safefree(sshc->readdir_longentry);
- sshc->readdir_longentry = NULL;
- state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = CURLE_OUT_OF_MEMORY;
- break;
- }
+ case SSH_SFTP_READDIR_LINK:
+ sshc->readdir_len = libssh2_sftp_readlink(sshc->sftp_session,
+ sshc->readdir_linkPath,
+ sshc->readdir_filename,
+ PATH_MAX);
+ if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+ Curl_safefree(sshc->readdir_linkPath);
+ sshc->readdir_linkPath = NULL;
+ sshc->readdir_line = realloc(sshc->readdir_line,
+ sshc->readdir_totalLen + 4 +
+ sshc->readdir_len);
+ if(!sshc->readdir_line) {
+ Curl_safefree(sshc->readdir_filename);
+ sshc->readdir_filename = NULL;
+ Curl_safefree(sshc->readdir_longentry);
+ sshc->readdir_longentry = NULL;
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
- sshc->readdir_currLen += snprintf(sshc->readdir_line +
- sshc->readdir_currLen,
- sshc->readdir_totalLen -
- sshc->readdir_currLen,
- " -> %s",
- sshc->readdir_filename);
+ sshc->readdir_currLen += snprintf(sshc->readdir_line +
+ sshc->readdir_currLen,
+ sshc->readdir_totalLen -
+ sshc->readdir_currLen,
+ " -> %s",
+ sshc->readdir_filename);
- state(conn, SSH_SFTP_READDIR_BOTTOM);
- break;
+ state(conn, SSH_SFTP_READDIR_BOTTOM);
+ break;
- case SSH_SFTP_READDIR_BOTTOM:
- sshc->readdir_currLen += snprintf(sshc->readdir_line +
- sshc->readdir_currLen,
- sshc->readdir_totalLen -
- sshc->readdir_currLen, "\n");
- result = Curl_client_write(conn, CLIENTWRITE_BODY,
- sshc->readdir_line,
- sshc->readdir_currLen);
+ case SSH_SFTP_READDIR_BOTTOM:
+ sshc->readdir_currLen += snprintf(sshc->readdir_line +
+ sshc->readdir_currLen,
+ sshc->readdir_totalLen -
+ sshc->readdir_currLen, "\n");
+ result = Curl_client_write(conn, CLIENTWRITE_BODY,
+ sshc->readdir_line,
+ sshc->readdir_currLen);
- if(result == CURLE_OK) {
+ if(result == CURLE_OK) {
- /* output debug output if that is requested */
- if(data->set.verbose) {
- Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line,
- sshc->readdir_currLen, conn);
+ /* output debug output if that is requested */
+ if(data->set.verbose) {
+ Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line,
+ sshc->readdir_currLen, conn);
+ }
+ data->req.bytecount += sshc->readdir_currLen;
}
- data->req.bytecount += sshc->readdir_currLen;
- }
- Curl_safefree(sshc->readdir_line);
- sshc->readdir_line = NULL;
- if(result) {
- state(conn, SSH_STOP);
- }
- else
- state(conn, SSH_SFTP_READDIR);
- break;
-
- case SSH_SFTP_READDIR_DONE:
- if(libssh2_sftp_closedir(sshc->sftp_handle) ==
- LIBSSH2_ERROR_EAGAIN) {
- rc = LIBSSH2_ERROR_EAGAIN;
+ Curl_safefree(sshc->readdir_line);
+ sshc->readdir_line = NULL;
+ if(result) {
+ state(conn, SSH_STOP);
+ }
+ else
+ state(conn, SSH_SFTP_READDIR);
break;
- }
- sshc->sftp_handle = NULL;
- Curl_safefree(sshc->readdir_filename);
- sshc->readdir_filename = NULL;
- Curl_safefree(sshc->readdir_longentry);
- sshc->readdir_longentry = NULL;
-
- /* no data to transfer */
- result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
- state(conn, SSH_STOP);
- break;
- case SSH_SFTP_DOWNLOAD_INIT:
- /*
- * Work on getting the specified file
- */
- sshc->sftp_handle =
- libssh2_sftp_open(sshc->sftp_session, sftp_scp->path,
- LIBSSH2_FXF_READ, data->set.new_file_perms);
- if(!sshc->sftp_handle) {
- if(libssh2_session_last_errno(sshc->ssh_session) ==
+ case SSH_SFTP_READDIR_DONE:
+ if(libssh2_sftp_closedir(sshc->sftp_handle) ==
LIBSSH2_ERROR_EAGAIN) {
rc = LIBSSH2_ERROR_EAGAIN;
break;
}
- else {
- err = libssh2_sftp_last_error(sshc->sftp_session);
- failf(data, "Could not open remote file for reading: %s",
- sftp_libssh2_strerror(err));
- state(conn, SSH_SFTP_CLOSE);
- result = sftp_libssh2_error_to_CURLE(err);
- sshc->actualcode = result?result:CURLE_SSH;
- break;
- }
- }
- state(conn, SSH_SFTP_DOWNLOAD_STAT);
- break;
-
- case SSH_SFTP_DOWNLOAD_STAT:
- {
- LIBSSH2_SFTP_ATTRIBUTES attrs;
+ sshc->sftp_handle = NULL;
+ Curl_safefree(sshc->readdir_filename);
+ sshc->readdir_filename = NULL;
+ Curl_safefree(sshc->readdir_longentry);
+ sshc->readdir_longentry = NULL;
- rc = libssh2_sftp_stat(sshc->sftp_session, sftp_scp->path, &attrs);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
+ /* no data to transfer */
+ result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ state(conn, SSH_STOP);
break;
- }
- else if(rc) {
+
+ case SSH_SFTP_DOWNLOAD_INIT:
/*
- * libssh2_sftp_open() didn't return an error, so maybe the server
- * just doesn't support stat()
+ * Work on getting the specified file
*/
- data->req.size = -1;
- data->req.maxdownload = -1;
- }
- else {
- curl_off_t size;
-
- size = attrs.filesize;
- if(conn->data->state.use_range) {
- curl_off_t from, to;
- char *ptr;
- char *ptr2;
-
- from=curlx_strtoofft(conn->data->state.range, &ptr, 0);
- while(ptr && *ptr && (isspace((int)*ptr) || (*ptr=='-')))
- ptr++;
- to=curlx_strtoofft(ptr, &ptr2, 0);
- if((ptr == ptr2) /* no "to" value given */
- || (to >= size)) {
- to = size - 1;
- }
- if(from < 0) {
- /* from is relative to end of file */
- from += size;
- }
- if(from >= size) {
- failf(data, "Offset (%"
- FORMAT_OFF_T ") was beyond file size (%" FORMAT_OFF_T ")",
- from, attrs.filesize);
- return CURLE_BAD_DOWNLOAD_RESUME;
- }
- if(from > to) {
- from = to;
- size = 0;
+ sshc->sftp_handle =
+ libssh2_sftp_open(sshc->sftp_session, sftp_scp->path,
+ LIBSSH2_FXF_READ, data->set.new_file_perms);
+ if(!sshc->sftp_handle) {
+ if(libssh2_session_last_errno(sshc->ssh_session) ==
+ LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
}
else {
- size = to - from + 1;
+ err = libssh2_sftp_last_error(sshc->sftp_session);
+ failf(data, "Could not open remote file for reading: %s",
+ sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ result = sftp_libssh2_error_to_CURLE(err);
+ sshc->actualcode = result?result:CURLE_SSH;
+ break;
}
-
- SFTP_SEEK(conn->proto.sshc.sftp_handle, from);
}
- data->req.size = size;
- data->req.maxdownload = size;
- Curl_pgrsSetDownloadSize(data, size);
- }
+ state(conn, SSH_SFTP_DOWNLOAD_STAT);
+ break;
- /* We can resume if we can seek to the resume position */
- if(data->state.resume_from) {
- if(data->state.resume_from< 0) {
- /* We're supposed to download the last abs(from) bytes */
- if((curl_off_t)attrs.filesize < -data->state.resume_from) {
- failf(data, "Offset (%"
- FORMAT_OFF_T ") was beyond file size (%" FORMAT_OFF_T ")",
- data->state.resume_from, attrs.filesize);
- return CURLE_BAD_DOWNLOAD_RESUME;
- }
- /* download from where? */
- data->state.resume_from = attrs.filesize - data->state.resume_from;
+ case SSH_SFTP_DOWNLOAD_STAT:
+ {
+ LIBSSH2_SFTP_ATTRIBUTES attrs;
+
+ rc = libssh2_sftp_stat(sshc->sftp_session, sftp_scp->path, &attrs);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc) {
+ /*
+ * libssh2_sftp_open() didn't return an error, so maybe the server
+ * just doesn't support stat()
+ */
+ data->req.size = -1;
+ data->req.maxdownload = -1;
}
else {
- if((curl_off_t)attrs.filesize < data->state.resume_from) {
- failf(data, "Offset (%" FORMAT_OFF_T
- ") was beyond file size (%" FORMAT_OFF_T ")",
- data->state.resume_from, attrs.filesize);
- return CURLE_BAD_DOWNLOAD_RESUME;
- }
- }
- /* Does a completed file need to be seeked and started or closed ? */
- /* Now store the number of bytes we are expected to download */
- data->req.size = attrs.filesize - data->state.resume_from;
- data->req.maxdownload = attrs.filesize - data->state.resume_from;
- Curl_pgrsSetDownloadSize(data,
- attrs.filesize - data->state.resume_from);
- SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
+ curl_off_t size;
+
+ size = attrs.filesize;
+ if(conn->data->state.use_range) {
+ curl_off_t from, to;
+ char *ptr;
+ char *ptr2;
+
+ from=curlx_strtoofft(conn->data->state.range, &ptr, 0);
+ while(ptr && *ptr && (isspace((int)*ptr) || (*ptr=='-')))
+ ptr++;
+ to=curlx_strtoofft(ptr, &ptr2, 0);
+ if((ptr == ptr2) /* no "to" value given */
+ || (to >= size)) {
+ to = size - 1;
+ }
+ if(from < 0) {
+ /* from is relative to end of file */
+ from += size;
+ }
+ if(from >= size) {
+ failf(data, "Offset (%"
+ FORMAT_OFF_T ") was beyond file size (%" FORMAT_OFF_T ")",
+ from, attrs.filesize);
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+ if(from > to) {
+ from = to;
+ size = 0;
+ }
+ else {
+ size = to - from + 1;
+ }
+
+ SFTP_SEEK(conn->proto.sshc.sftp_handle, from);
+ }
+ 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're supposed to download the last abs(from) bytes */
+ if((curl_off_t)attrs.filesize < -data->state.resume_from) {
+ failf(data, "Offset (%"
+ FORMAT_OFF_T ") was beyond file size (%" FORMAT_OFF_T ")",
+ data->state.resume_from, attrs.filesize);
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+ /* download from where? */
+ data->state.resume_from = attrs.filesize - data->state.resume_from;
+ }
+ else {
+ if((curl_off_t)attrs.filesize < data->state.resume_from) {
+ failf(data, "Offset (%" FORMAT_OFF_T
+ ") was beyond file size (%" FORMAT_OFF_T ")",
+ data->state.resume_from, attrs.filesize);
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+ }
+ /* Does a completed file need to be seeked and started or closed ? */
+ /* Now store the number of bytes we are expected to download */
+ data->req.size = attrs.filesize - data->state.resume_from;
+ data->req.maxdownload = attrs.filesize - data->state.resume_from;
+ Curl_pgrsSetDownloadSize(data,
+ attrs.filesize - data->state.resume_from);
+ SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
+ }
+ }
+ /* Setup the actual download */
+ if(data->req.size == 0) {
+ /* no data to transfer */
+ result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ infof(data, "File already completely downloaded\n");
+ state(conn, SSH_STOP);
+ break;
}
- }
- /* Setup the actual download */
- if(data->req.size == 0) {
- /* no data to transfer */
- result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
- infof(data, "File already completely downloaded\n");
- state(conn, SSH_STOP);
- break;
- }
- else {
- result = Curl_setup_transfer(conn, FIRSTSOCKET, data->req.size,
- FALSE, NULL, -1, NULL);
+ else {
+ result = Curl_setup_transfer(conn, FIRSTSOCKET, data->req.size,
+ FALSE, NULL, -1, NULL);
- /* not set by Curl_setup_transfer to preserve keepon bits */
- conn->writesockfd = conn->sockfd;
+ /* not set by Curl_setup_transfer to preserve keepon bits */
+ conn->writesockfd = conn->sockfd;
- /* FIXME: here should be explained why we need it to start the download */
- conn->cselect_bits = CURL_CSELECT_IN;
- }
- if(result) {
- state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = result;
- }
- else {
- state(conn, SSH_STOP);
- }
- break;
+ /* FIXME: here should be explained why we need it to start the download */
+ conn->cselect_bits = CURL_CSELECT_IN;
+ }
+ if(result) {
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = result;
+ }
+ else {
+ state(conn, SSH_STOP);
+ }
+ break;
- case SSH_SFTP_CLOSE:
- if(sshc->sftp_handle) {
- rc = libssh2_sftp_close(sshc->sftp_handle);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
- }
- else if(rc < 0) {
- infof(data, "Failed to close libssh2 file\n");
+ case SSH_SFTP_CLOSE:
+ if(sshc->sftp_handle) {
+ rc = libssh2_sftp_close(sshc->sftp_handle);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc < 0) {
+ infof(data, "Failed to close libssh2 file\n");
+ }
+ sshc->sftp_handle = NULL;
}
- sshc->sftp_handle = NULL;
- }
- Curl_safefree(sftp_scp->path);
- sftp_scp->path = NULL;
+ Curl_safefree(sftp_scp->path);
+ sftp_scp->path = NULL;
- DEBUGF(infof(data, "SFTP DONE done\n"));
+ DEBUGF(infof(data, "SFTP DONE done\n"));
#if 0 /* PREV */
- state(conn, SSH_SFTP_SHUTDOWN);
+ state(conn, SSH_SFTP_SHUTDOWN);
#endif
- state(conn, SSH_STOP);
- result = sshc->actualcode;
- break;
+ state(conn, SSH_STOP);
+ result = sshc->actualcode;
+ break;
- case SSH_SFTP_SHUTDOWN:
- /* during times we get here due to a broken transfer and then the
- sftp_handle might not have been taken down so make sure that is done
- before we proceed */
+ case SSH_SFTP_SHUTDOWN:
+ /* during times we get here due to a broken transfer and then the
+ sftp_handle might not have been taken down so make sure that is done
+ before we proceed */
- if(sshc->sftp_handle) {
- rc = libssh2_sftp_close(sshc->sftp_handle);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
- }
- else if(rc < 0) {
- infof(data, "Failed to close libssh2 file\n");
- }
- sshc->sftp_handle = NULL;
- }
- if(sshc->sftp_session) {
- rc = libssh2_sftp_shutdown(sshc->sftp_session);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
+ if(sshc->sftp_handle) {
+ rc = libssh2_sftp_close(sshc->sftp_handle);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc < 0) {
+ infof(data, "Failed to close libssh2 file\n");
+ }
+ sshc->sftp_handle = NULL;
}
- else if(rc < 0) {
- infof(data, "Failed to stop libssh2 sftp subsystem\n");
+ if(sshc->sftp_session) {
+ rc = libssh2_sftp_shutdown(sshc->sftp_session);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc < 0) {
+ infof(data, "Failed to stop libssh2 sftp subsystem\n");
+ }
+ sshc->sftp_session = NULL;
}
- sshc->sftp_session = NULL;
- }
- Curl_safefree(sshc->homedir);
- sshc->homedir = NULL;
+ Curl_safefree(sshc->homedir);
+ sshc->homedir = NULL;
- state(conn, SSH_SESSION_DISCONNECT);
- break;
-
- case SSH_SCP_TRANS_INIT:
- result = ssh_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
- if(result) {
- sshc->actualcode = result;
- state(conn, SSH_STOP);
+ state(conn, SSH_SESSION_DISCONNECT);
break;
- }
- if(data->set.upload) {
- if(data->set.infilesize < 0) {
- failf(data, "SCP requires a known file size for upload");
- sshc->actualcode = CURLE_UPLOAD_FAILED;
- state(conn, SSH_SCP_CHANNEL_FREE);
+ case SSH_SCP_TRANS_INIT:
+ result = ssh_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
+ if(result) {
+ sshc->actualcode = result;
+ state(conn, SSH_STOP);
break;
}
- state(conn, SSH_SCP_UPLOAD_INIT);
- }
- else {
- state(conn, SSH_SCP_DOWNLOAD_INIT);
- }
- break;
- case SSH_SCP_UPLOAD_INIT:
- /*
- * libssh2 requires that the destination path is a full path that
- * includes the destination file and name OR ends in a "/" . If this is
- * not done the destination file will be named the same name as the last
- * directory in the path.
- */
- sshc->ssh_channel =
- libssh2_scp_send_ex(sshc->ssh_session, sftp_scp->path,
- data->set.new_file_perms,
- (size_t)data->set.infilesize, 0, 0);
- if(!sshc->ssh_channel) {
- if(libssh2_session_last_errno(sshc->ssh_session) ==
- LIBSSH2_ERROR_EAGAIN) {
- rc = LIBSSH2_ERROR_EAGAIN;
- break;
+ if(data->set.upload) {
+ if(data->set.infilesize < 0) {
+ failf(data, "SCP requires a known file size for upload");
+ sshc->actualcode = CURLE_UPLOAD_FAILED;
+ state(conn, SSH_SCP_CHANNEL_FREE);
+ break;
+ }
+ state(conn, SSH_SCP_UPLOAD_INIT);
}
else {
- int ssh_err;
- char *err_msg;
-
- ssh_err = libssh2_session_last_error(sshc->ssh_session,
- &err_msg, NULL, 0);
- failf(conn->data, "%s", err_msg);
- state(conn, SSH_SCP_CHANNEL_FREE);
- sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
- break;
+ state(conn, SSH_SCP_DOWNLOAD_INIT);
}
- }
+ break;
- /* upload data */
- result = Curl_setup_transfer(conn, -1, data->req.size, FALSE, NULL,
- FIRSTSOCKET, NULL);
+ case SSH_SCP_UPLOAD_INIT:
+ /*
+ * libssh2 requires that the destination path is a full path that
+ * includes the destination file and name OR ends in a "/" . If this is
+ * not done the destination file will be named the same name as the last
+ * directory in the path.
+ */
+ sshc->ssh_channel =
+ libssh2_scp_send_ex(sshc->ssh_session, sftp_scp->path,
+ data->set.new_file_perms,
+ (size_t)data->set.infilesize, 0, 0);
+ if(!sshc->ssh_channel) {
+ if(libssh2_session_last_errno(sshc->ssh_session) ==
+ LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+ else {
+ int ssh_err;
+ char *err_msg;
+
+ ssh_err = libssh2_session_last_error(sshc->ssh_session,
+ &err_msg, NULL, 0);
+ failf(conn->data, "%s", err_msg);
+ state(conn, SSH_SCP_CHANNEL_FREE);
+ sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
+ break;
+ }
+ }
- /* not set by Curl_setup_transfer to preserve keepon bits */
- conn->sockfd = conn->writesockfd;
+ /* upload data */
+ result = Curl_setup_transfer(conn, -1, data->req.size, FALSE, NULL,
+ FIRSTSOCKET, NULL);
- if(result) {
- state(conn, SSH_SCP_CHANNEL_FREE);
- sshc->actualcode = result;
- }
- else {
- state(conn, SSH_STOP);
- }
- break;
+ /* not set by Curl_setup_transfer to preserve keepon bits */
+ conn->sockfd = conn->writesockfd;
- case SSH_SCP_DOWNLOAD_INIT:
- {
- /*
- * We must check the remote file; if it is a directory no values will
- * be set in sb
- */
- struct stat sb;
- curl_off_t bytecount;
-
- /* clear the struct scp recv will fill in */
- memset(&sb, 0, sizeof(struct stat));
-
- /* get a fresh new channel from the ssh layer */
- sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session,
- sftp_scp->path, &sb);
- if(!sshc->ssh_channel) {
- if(libssh2_session_last_errno(sshc->ssh_session) ==
- LIBSSH2_ERROR_EAGAIN) {
- rc = LIBSSH2_ERROR_EAGAIN;
- break;
+ if(result) {
+ state(conn, SSH_SCP_CHANNEL_FREE);
+ sshc->actualcode = result;
}
else {
- int ssh_err;
- char *err_msg;
-
- ssh_err = libssh2_session_last_error(sshc->ssh_session,
- &err_msg, NULL, 0);
- failf(conn->data, "%s", err_msg);
- state(conn, SSH_SCP_CHANNEL_FREE);
- sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
- break;
+ state(conn, SSH_STOP);
}
- }
-
- /* download data */
- bytecount = (curl_off_t)sb.st_size;
- data->req.maxdownload = (curl_off_t)sb.st_size;
- result = Curl_setup_transfer(conn, FIRSTSOCKET,
- bytecount, FALSE, NULL, -1, NULL);
+ break;
- /* not set by Curl_setup_transfer to preserve keepon bits */
- conn->writesockfd = conn->sockfd;
+ case SSH_SCP_DOWNLOAD_INIT:
+ {
+ /*
+ * We must check the remote file; if it is a directory no values will
+ * be set in sb
+ */
+ struct stat sb;
+ curl_off_t bytecount;
+
+ /* clear the struct scp recv will fill in */
+ memset(&sb, 0, sizeof(struct stat));
+
+ /* get a fresh new channel from the ssh layer */
+ sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session,
+ sftp_scp->path, &sb);
+ if(!sshc->ssh_channel) {
+ if(libssh2_session_last_errno(sshc->ssh_session) ==
+ LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+ else {
+ int ssh_err;
+ char *err_msg;
+
+ ssh_err = libssh2_session_last_error(sshc->ssh_session,
+ &err_msg, NULL, 0);
+ failf(conn->data, "%s", err_msg);
+ state(conn, SSH_SCP_CHANNEL_FREE);
+ sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
+ break;
+ }
+ }
- /* FIXME: here should be explained why we need it to start the download */
- conn->cselect_bits = CURL_CSELECT_IN;
+ /* download data */
+ bytecount = (curl_off_t)sb.st_size;
+ data->req.maxdownload = (curl_off_t)sb.st_size;
+ result = Curl_setup_transfer(conn, FIRSTSOCKET,
+ bytecount, FALSE, NULL, -1, NULL);
- if(result) {
- state(conn, SSH_SCP_CHANNEL_FREE);
- sshc->actualcode = result;
- }
- else
- state(conn, SSH_STOP);
- }
- break;
+ /* not set by Curl_setup_transfer to preserve keepon bits */
+ conn->writesockfd = conn->sockfd;
- case SSH_SCP_DONE:
- if(data->set.upload)
- state(conn, SSH_SCP_SEND_EOF);
- else
- state(conn, SSH_SCP_CHANNEL_FREE);
- break;
+ /* FIXME: here should be explained why we need it to start the download */
+ conn->cselect_bits = CURL_CSELECT_IN;
- case SSH_SCP_SEND_EOF:
- if(sshc->ssh_channel) {
- rc = libssh2_channel_send_eof(sshc->ssh_channel);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
- }
- else if(rc) {
- infof(data, "Failed to send libssh2 channel EOF\n");
+ if(result) {
+ state(conn, SSH_SCP_CHANNEL_FREE);
+ sshc->actualcode = result;
}
+ else
+ state(conn, SSH_STOP);
}
- state(conn, SSH_SCP_WAIT_EOF);
break;
- case SSH_SCP_WAIT_EOF:
- if(sshc->ssh_channel) {
- rc = libssh2_channel_wait_eof(sshc->ssh_channel);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
- }
- else if(rc) {
- infof(data, "Failed to get channel EOF: %d\n", rc);
- }
- }
- state(conn, SSH_SCP_WAIT_CLOSE);
- break;
+ case SSH_SCP_DONE:
+ if(data->set.upload)
+ state(conn, SSH_SCP_SEND_EOF);
+ else
+ state(conn, SSH_SCP_CHANNEL_FREE);
+ break;
- case SSH_SCP_WAIT_CLOSE:
- if(sshc->ssh_channel) {
- rc = libssh2_channel_wait_closed(sshc->ssh_channel);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
+ case SSH_SCP_SEND_EOF:
+ if(sshc->ssh_channel) {
+ rc = libssh2_channel_send_eof(sshc->ssh_channel);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc) {
+ infof(data, "Failed to send libssh2 channel EOF\n");
+ }
}
- else if(rc) {
- infof(data, "Channel failed to close: %d\n", rc);
+ state(conn, SSH_SCP_WAIT_EOF);
+ break;
+
+ case SSH_SCP_WAIT_EOF:
+ if(sshc->ssh_channel) {
+ rc = libssh2_channel_wait_eof(sshc->ssh_channel);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc) {
+ infof(data, "Failed to get channel EOF: %d\n", rc);
+ }
}
- }
- state(conn, SSH_SCP_CHANNEL_FREE);
- break;
+ state(conn, SSH_SCP_WAIT_CLOSE);
+ break;
- case SSH_SCP_CHANNEL_FREE:
- if(sshc->ssh_channel) {
- rc = libssh2_channel_free(sshc->ssh_channel);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
+ case SSH_SCP_WAIT_CLOSE:
+ if(sshc->ssh_channel) {
+ rc = libssh2_channel_wait_closed(sshc->ssh_channel);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc) {
+ infof(data, "Channel failed to close: %d\n", rc);
+ }
}
- else if(rc < 0) {
- infof(data, "Failed to free libssh2 scp subsystem\n");
+ state(conn, SSH_SCP_CHANNEL_FREE);
+ break;
+
+ case SSH_SCP_CHANNEL_FREE:
+ if(sshc->ssh_channel) {
+ rc = libssh2_channel_free(sshc->ssh_channel);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc < 0) {
+ infof(data, "Failed to free libssh2 scp subsystem\n");
+ }
+ sshc->ssh_channel = NULL;
}
- sshc->ssh_channel = NULL;
- }
- DEBUGF(infof(data, "SCP DONE phase complete\n"));
+ DEBUGF(infof(data, "SCP DONE phase complete\n"));
#if 0 /* PREV */
- state(conn, SSH_SESSION_DISCONNECT);
+ state(conn, SSH_SESSION_DISCONNECT);
#endif
- state(conn, SSH_STOP);
- result = sshc->actualcode;
- break;
+ state(conn, SSH_STOP);
+ result = sshc->actualcode;
+ break;
- case SSH_SESSION_DISCONNECT:
- /* during weird times when we've been prematurely aborted, the channel
- is still alive when we reach this state and we MUST kill the channel
- properly first */
- if(sshc->ssh_channel) {
- rc = libssh2_channel_free(sshc->ssh_channel);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
- }
- else if(rc < 0) {
- infof(data, "Failed to free libssh2 scp subsystem\n");
+ case SSH_SESSION_DISCONNECT:
+ /* during weird times when we've been prematurely aborted, the channel
+ is still alive when we reach this state and we MUST kill the channel
+ properly first */
+ if(sshc->ssh_channel) {
+ rc = libssh2_channel_free(sshc->ssh_channel);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc < 0) {
+ infof(data, "Failed to free libssh2 scp subsystem\n");
+ }
+ sshc->ssh_channel = NULL;
}
- sshc->ssh_channel = NULL;
- }
- if(sshc->ssh_session) {
- rc = libssh2_session_disconnect(sshc->ssh_session, "Shutdown");
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
- }
- else if(rc < 0) {
- infof(data, "Failed to disconnect libssh2 session\n");
+ if(sshc->ssh_session) {
+ rc = libssh2_session_disconnect(sshc->ssh_session, "Shutdown");
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc < 0) {
+ infof(data, "Failed to disconnect libssh2 session\n");
+ }
}
- }
- Curl_safefree(sshc->homedir);
- sshc->homedir = NULL;
+ Curl_safefree(sshc->homedir);
+ sshc->homedir = NULL;
- state(conn, SSH_SESSION_FREE);
- break;
+ state(conn, SSH_SESSION_FREE);
+ break;
- case SSH_SESSION_FREE:
+ case SSH_SESSION_FREE:
#ifdef HAVE_LIBSSH2_KNOWNHOST_API
- if(sshc->kh) {
- libssh2_knownhost_free(sshc->kh);
- sshc->kh = NULL;
- }
+ if(sshc->kh) {
+ libssh2_knownhost_free(sshc->kh);
+ sshc->kh = NULL;
+ }
#endif
- if(sshc->ssh_session) {
- rc = libssh2_session_free(sshc->ssh_session);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
- }
- else if(rc < 0) {
- infof(data, "Failed to free libssh2 session\n");
+ if(sshc->ssh_session) {
+ rc = libssh2_session_free(sshc->ssh_session);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc < 0) {
+ infof(data, "Failed to free libssh2 session\n");
+ }
+ sshc->ssh_session = NULL;
}
- sshc->ssh_session = NULL;
+ conn->bits.close = TRUE;
+ sshc->nextstate = SSH_NO_STATE;
+ state(conn, SSH_STOP);
+ result = sshc->actualcode;
+ break;
+
+ case SSH_QUIT:
+ /* fallthrough, just stop! */
+ default:
+ /* internal error */
+ sshc->nextstate = SSH_NO_STATE;
+ state(conn, SSH_STOP);
+ break;
}
- conn->bits.close = TRUE;
- sshc->nextstate = SSH_NO_STATE;
- state(conn, SSH_STOP);
- result = sshc->actualcode;
- break;
- case SSH_QUIT:
- /* fallthrough, just stop! */
- default:
- /* internal error */
- sshc->nextstate = SSH_NO_STATE;
- state(conn, SSH_STOP);
- break;
- }
+ } while(!rc && (sshc->state != SSH_STOP));
if(rc == LIBSSH2_ERROR_EAGAIN) {
/* we would block, we need to wait for the socket to be ready (in the