return SSH_NO_ERROR;
}
+static void myssh_quote_error(struct Curl_easy *data, struct ssh_conn *sshc,
+ const char *cmd)
+{
+ if(cmd)
+ failf(data, "%s command failed: %s", cmd,
+ ssh_get_error(sshc->ssh_session));
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+ myssh_to(data, sshc, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+}
+
static int myssh_in_SFTP_QUOTE_STATVFS(struct Curl_easy *data,
struct ssh_conn *sshc)
{
statvfs = sftp_statvfs(sshc->sftp_session, sshc->quote_path1);
if(!statvfs && !sshc->acceptfail) {
- Curl_safefree(sshc->quote_path1);
- failf(data, "statvfs command failed: %s",
- ssh_get_error(sshc->ssh_session));
- myssh_to(data, sshc, SSH_SFTP_CLOSE);
- sshc->nextstate = SSH_NO_STATE;
- sshc->actualcode = CURLE_QUOTE_ERROR;
+ myssh_quote_error(data, sshc, "statvfs");
return SSH_OK;
}
else if(statvfs) {
sftp_attributes_free(sshc->quote_attrs);
sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2);
if(!sshc->quote_attrs) {
- Curl_safefree(sshc->quote_path1);
- Curl_safefree(sshc->quote_path2);
failf(data, "Attempt to get SFTP stats failed: %d",
sftp_get_error(sshc->sftp_session));
- myssh_to(data, sshc, SSH_SFTP_CLOSE);
- sshc->nextstate = SSH_NO_STATE;
- sshc->actualcode = CURLE_QUOTE_ERROR;
+ myssh_quote_error(data, sshc, NULL);
return SSH_NO_ERROR;
}
const char *p = sshc->quote_path1;
curl_off_t gid;
if(curlx_str_number(&p, &gid, UINT_MAX)) {
- Curl_safefree(sshc->quote_path1);
- Curl_safefree(sshc->quote_path2);
failf(data, "Syntax error: chgrp gid not a number");
- myssh_to(data, sshc, SSH_SFTP_CLOSE);
- sshc->nextstate = SSH_NO_STATE;
- sshc->actualcode = CURLE_QUOTE_ERROR;
+ myssh_quote_error(data, sshc, NULL);
return SSH_NO_ERROR;
}
sshc->quote_attrs->gid = (uint32_t)gid;
curl_off_t perms;
const char *p = sshc->quote_path1;
if(curlx_str_octal(&p, &perms, 07777)) {
- Curl_safefree(sshc->quote_path1);
- Curl_safefree(sshc->quote_path2);
failf(data, "Syntax error: chmod permissions not a number");
- myssh_to(data, sshc, SSH_SFTP_CLOSE);
- sshc->nextstate = SSH_NO_STATE;
- sshc->actualcode = CURLE_QUOTE_ERROR;
+ myssh_quote_error(data, sshc, NULL);
return SSH_NO_ERROR;
}
sshc->quote_attrs->permissions = (mode_t)perms;
const char *p = sshc->quote_path1;
curl_off_t uid;
if(curlx_str_number(&p, &uid, UINT_MAX)) {
- Curl_safefree(sshc->quote_path1);
- Curl_safefree(sshc->quote_path2);
failf(data, "Syntax error: chown uid not a number");
- myssh_to(data, sshc, SSH_SFTP_CLOSE);
- sshc->nextstate = SSH_NO_STATE;
- sshc->actualcode = CURLE_QUOTE_ERROR;
+ myssh_quote_error(data, sshc, NULL);
return SSH_NO_ERROR;
}
sshc->quote_attrs->uid = (uint32_t)uid;
}
#endif
if(fail) {
- Curl_safefree(sshc->quote_path1);
- Curl_safefree(sshc->quote_path2);
- myssh_to(data, sshc, SSH_SFTP_CLOSE);
- sshc->nextstate = SSH_NO_STATE;
- sshc->actualcode = CURLE_QUOTE_ERROR;
+ myssh_quote_error(data, sshc, NULL);
return SSH_NO_ERROR;
}
if(date > UINT_MAX)
}
}
+static void myssh_SESSION_DISCONNECT(struct Curl_easy *data,
+ struct ssh_conn *sshc)
+{
+ /* during weird times when we have been prematurely aborted, the channel
+ is still alive when we reach this state and we MUST kill the channel
+ properly first */
+ if(sshc->scp_session) {
+ ssh_scp_free(sshc->scp_session);
+ sshc->scp_session = NULL;
+ }
+
+ if(sshc->sftp_file) {
+ sftp_close(sshc->sftp_file);
+ sshc->sftp_file = NULL;
+ }
+ if(sshc->sftp_session) {
+ sftp_free(sshc->sftp_session);
+ sshc->sftp_session = NULL;
+ }
+
+ ssh_disconnect(sshc->ssh_session);
+ if(!ssh_version(SSH_VERSION_INT(0, 10, 0))) {
+ /* conn->sock[FIRSTSOCKET] is closed by ssh_disconnect behind our back,
+ tell the connection to forget about it. This libssh
+ bug is fixed in 0.10.0. */
+ conn_forget_socket(data, FIRSTSOCKET);
+ }
+
+ SSH_STRING_FREE_CHAR(sshc->homedir);
+
+ myssh_to(data, sshc, SSH_SESSION_FREE);
+}
+
+static int myssh_SSH_SCP_DOWNLOAD(struct Curl_easy *data,
+ struct ssh_conn *sshc)
+{
+ curl_off_t bytecount;
+ int rc = ssh_scp_pull_request(sshc->scp_session);
+ if(rc != SSH_SCP_REQUEST_NEWFILE) {
+ const char *err_msg = ssh_get_error(sshc->ssh_session);
+ failf(data, "%s", err_msg);
+ return myssh_to_ERROR(data, sshc, CURLE_REMOTE_FILE_NOT_FOUND);
+ }
+
+ /* download data */
+ bytecount = ssh_scp_request_get_size(sshc->scp_session);
+ data->req.maxdownload = (curl_off_t)bytecount;
+ Curl_xfer_setup_recv(data, FIRSTSOCKET, bytecount);
+
+ /* not set by Curl_xfer_setup to preserve keepon bits */
+ data->conn->send_idx = 0;
+
+ myssh_to(data, sshc, SSH_STOP);
+ return 0;
+}
+
+static int myssh_in_TRANS_INIT(struct Curl_easy *data, struct ssh_conn *sshc,
+ struct SSHPROTO *sshp)
+{
+ CURLcode result;
+ int rc = 0;
+ if(!sshp)
+ return myssh_to_ERROR(data, sshc, CURLE_FAILED_INIT);
+
+ result = Curl_getworkingpath(data, sshc->homedir, &sshp->path);
+ if(result) {
+ sshc->actualcode = result;
+ myssh_to(data, sshc, SSH_STOP);
+ return 0;
+ }
+
+ /* Functions from the SCP subsystem cannot handle/return SSH_AGAIN */
+ ssh_set_blocking(sshc->ssh_session, 1);
+
+ if(data->state.upload) {
+ if(data->state.infilesize < 0) {
+ failf(data, "SCP requires a known file size for upload");
+ return myssh_to_ERROR(data, sshc, CURLE_UPLOAD_FAILED);
+ }
+
+ sshc->scp_session =
+ ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, sshp->path);
+ myssh_to(data, sshc, SSH_SCP_UPLOAD_INIT);
+ }
+ else {
+ sshc->scp_session =
+ ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, sshp->path);
+ myssh_to(data, sshc, SSH_SCP_DOWNLOAD_INIT);
+ }
+
+ if(!sshc->scp_session) {
+ const char *err_msg = ssh_get_error(sshc->ssh_session);
+ failf(data, "%s", err_msg);
+ rc = myssh_to_ERROR(data, sshc, CURLE_UPLOAD_FAILED);
+ }
+ return rc;
+}
+
/*
* ssh_statemach_act() runs the SSH state machine as far as it can without
* blocking and without reaching the end. The data the pointer 'block' points
bool *block)
{
CURLcode result = CURLE_OK;
- struct connectdata *conn = data->conn;
int rc = SSH_NO_ERROR, err;
- const char *err_msg;
*block = FALSE; /* we are not blocking by default */
do {
break;
case SSH_SFTP_QUOTE_INIT:
rc = sshp ? myssh_in_SFTP_QUOTE_INIT(data, sshc, sshp) :
- CURLE_FAILED_INIT;
+ CURLE_FAILED_INIT;
break;
case SSH_SFTP_POSTQUOTE_INIT:
rc = myssh_in_SFTP_POSTQUOTE_INIT(data, sshc);
break;
case SSH_SFTP_QUOTE:
- rc = sshp ? myssh_in_SFTP_QUOTE(data, sshc, sshp) :
- CURLE_FAILED_INIT;
+ rc = sshp ? myssh_in_SFTP_QUOTE(data, sshc, sshp) : CURLE_FAILED_INIT;
break;
case SSH_SFTP_NEXT_QUOTE:
rc = myssh_in_SFTP_NEXT_QUOTE(data, sshc);
case SSH_SFTP_QUOTE_STAT:
rc = myssh_in_SFTP_QUOTE_STAT(data, sshc);
break;
-
case SSH_SFTP_QUOTE_SETSTAT:
rc = sftp_setstat(sshc->sftp_session, sshc->quote_path2,
sshc->quote_attrs);
if(rc == SSH_AGAIN)
break;
if(rc && !sshc->acceptfail) {
- Curl_safefree(sshc->quote_path1);
- Curl_safefree(sshc->quote_path2);
- failf(data, "Attempt to set SFTP stats failed: %s",
- ssh_get_error(sshc->ssh_session));
- myssh_to(data, sshc, SSH_SFTP_CLOSE);
- sshc->nextstate = SSH_NO_STATE;
- sshc->actualcode = CURLE_QUOTE_ERROR;
- /* sshc->actualcode = sftp_error_to_CURLE(err);
- * we do not send the actual error; we return
- * the error the libssh2 backend is returning */
+ myssh_quote_error(data, sshc, "setstat");
break;
}
myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
if(rc == SSH_AGAIN)
break;
if(rc && !sshc->acceptfail) {
- Curl_safefree(sshc->quote_path1);
- Curl_safefree(sshc->quote_path2);
- failf(data, "symlink command failed: %s",
- ssh_get_error(sshc->ssh_session));
- myssh_to(data, sshc, SSH_SFTP_CLOSE);
- sshc->nextstate = SSH_NO_STATE;
- sshc->actualcode = CURLE_QUOTE_ERROR;
+ myssh_quote_error(data, sshc, "symlink");
break;
}
myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
if(rc == SSH_AGAIN)
break;
if(rc && !sshc->acceptfail) {
- Curl_safefree(sshc->quote_path1);
- failf(data, "mkdir command failed: %s",
- ssh_get_error(sshc->ssh_session));
- myssh_to(data, sshc, SSH_SFTP_CLOSE);
- sshc->nextstate = SSH_NO_STATE;
- sshc->actualcode = CURLE_QUOTE_ERROR;
+ myssh_quote_error(data, sshc, "mkdir");
break;
}
myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
if(rc == SSH_AGAIN)
break;
if(rc && !sshc->acceptfail) {
- Curl_safefree(sshc->quote_path1);
- Curl_safefree(sshc->quote_path2);
- failf(data, "rename command failed: %s",
- ssh_get_error(sshc->ssh_session));
- myssh_to(data, sshc, SSH_SFTP_CLOSE);
- sshc->nextstate = SSH_NO_STATE;
- sshc->actualcode = CURLE_QUOTE_ERROR;
+ myssh_quote_error(data, sshc, "rename");
break;
}
myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
if(rc == SSH_AGAIN)
break;
if(rc && !sshc->acceptfail) {
- Curl_safefree(sshc->quote_path1);
- failf(data, "rmdir command failed: %s",
- ssh_get_error(sshc->ssh_session));
- myssh_to(data, sshc, SSH_SFTP_CLOSE);
- sshc->nextstate = SSH_NO_STATE;
- sshc->actualcode = CURLE_QUOTE_ERROR;
+ myssh_quote_error(data, sshc, "rmdir");
break;
}
myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
if(rc == SSH_AGAIN)
break;
if(rc && !sshc->acceptfail) {
- Curl_safefree(sshc->quote_path1);
- failf(data, "rm command failed: %s", ssh_get_error(sshc->ssh_session));
- myssh_to(data, sshc, SSH_SFTP_CLOSE);
- sshc->nextstate = SSH_NO_STATE;
- sshc->actualcode = CURLE_QUOTE_ERROR;
+ myssh_quote_error(data, sshc, "rm");
break;
}
myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
case SSH_SFTP_READDIR_INIT:
rc = sshp ? myssh_in_SFTP_READDIR_INIT(data, sshc, sshp) :
- CURLE_FAILED_INIT;
+ CURLE_FAILED_INIT;
break;
case SSH_SFTP_READDIR:
- rc = sshp ? myssh_in_SFTP_READDIR(data, sshc, sshp) :
- CURLE_FAILED_INIT;
+ rc = sshp ? myssh_in_SFTP_READDIR(data, sshc, sshp) : CURLE_FAILED_INIT;
break;
case SSH_SFTP_READDIR_LINK:
rc = myssh_in_SFTP_READDIR_LINK(data, sshc);
break;
case SSH_SFTP_DOWNLOAD_INIT:
rc = sshp ? myssh_in_SFTP_DOWNLOAD_INIT(data, sshc, sshp) :
- CURLE_FAILED_INIT;
+ CURLE_FAILED_INIT;
break;
case SSH_SFTP_DOWNLOAD_STAT:
rc = myssh_in_SFTP_DOWNLOAD_STAT(data, sshc);
break;
case SSH_SFTP_CLOSE:
- rc = sshp ? myssh_in_SFTP_CLOSE(data, sshc, sshp) :
- CURLE_FAILED_INIT;
+ rc = sshp ? myssh_in_SFTP_CLOSE(data, sshc, sshp) : CURLE_FAILED_INIT;
break;
case SSH_SFTP_SHUTDOWN:
rc = myssh_in_SFTP_SHUTDOWN(data, sshc);
break;
-
case SSH_SCP_TRANS_INIT:
- if(!sshp) {
- result = CURLE_FAILED_INIT;
- break;
- }
- result = Curl_getworkingpath(data, sshc->homedir, &sshp->path);
- if(result) {
- sshc->actualcode = result;
- myssh_to(data, sshc, SSH_STOP);
- break;
- }
-
- /* Functions from the SCP subsystem cannot handle/return SSH_AGAIN */
- ssh_set_blocking(sshc->ssh_session, 1);
-
- if(data->state.upload) {
- if(data->state.infilesize < 0) {
- failf(data, "SCP requires a known file size for upload");
- sshc->actualcode = CURLE_UPLOAD_FAILED;
- rc = myssh_to_ERROR(data, sshc, CURLE_UPLOAD_FAILED);
- break;
- }
-
- sshc->scp_session =
- ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, sshp->path);
- myssh_to(data, sshc, SSH_SCP_UPLOAD_INIT);
- }
- else {
- sshc->scp_session =
- ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, sshp->path);
- myssh_to(data, sshc, SSH_SCP_DOWNLOAD_INIT);
- }
-
- if(!sshc->scp_session) {
- err_msg = ssh_get_error(sshc->ssh_session);
- failf(data, "%s", err_msg);
- rc = myssh_to_ERROR(data, sshc, CURLE_UPLOAD_FAILED);
- }
+ rc = myssh_in_TRANS_INIT(data, sshc, sshp);
break;
case SSH_SCP_UPLOAD_INIT:
}
rc = ssh_scp_init(sshc->scp_session);
if(rc != SSH_OK) {
- err_msg = ssh_get_error(sshc->ssh_session);
+ const char *err_msg = ssh_get_error(sshc->ssh_session);
failf(data, "%s", err_msg);
rc = myssh_to_ERROR(data, sshc, CURLE_UPLOAD_FAILED);
break;
(int)data->set.new_file_perms);
if(rc != SSH_OK) {
- err_msg = ssh_get_error(sshc->ssh_session);
+ const char *err_msg = ssh_get_error(sshc->ssh_session);
failf(data, "%s", err_msg);
rc = myssh_to_ERROR(data, sshc, CURLE_UPLOAD_FAILED);
break;
break;
case SSH_SCP_DOWNLOAD_INIT:
-
rc = ssh_scp_init(sshc->scp_session);
if(rc != SSH_OK) {
- err_msg = ssh_get_error(sshc->ssh_session);
+ const char *err_msg = ssh_get_error(sshc->ssh_session);
failf(data, "%s", err_msg);
rc = myssh_to_ERROR(data, sshc, CURLE_COULDNT_CONNECT);
break;
myssh_to(data, sshc, SSH_SCP_DOWNLOAD);
FALLTHROUGH();
- case SSH_SCP_DOWNLOAD: {
- curl_off_t bytecount;
-
- rc = ssh_scp_pull_request(sshc->scp_session);
- if(rc != SSH_SCP_REQUEST_NEWFILE) {
- err_msg = ssh_get_error(sshc->ssh_session);
- failf(data, "%s", err_msg);
- rc = myssh_to_ERROR(data, sshc, CURLE_REMOTE_FILE_NOT_FOUND);
- break;
- }
-
- /* download data */
- bytecount = ssh_scp_request_get_size(sshc->scp_session);
- data->req.maxdownload = (curl_off_t)bytecount;
- Curl_xfer_setup_recv(data, FIRSTSOCKET, bytecount);
-
- /* not set by Curl_xfer_setup to preserve keepon bits */
- conn->send_idx = 0;
-
- myssh_to(data, sshc, SSH_STOP);
+ case SSH_SCP_DOWNLOAD:
+ rc = myssh_SSH_SCP_DOWNLOAD(data, sshc);
break;
- }
+
case SSH_SCP_DONE:
if(data->state.upload)
myssh_to(data, sshc, SSH_SCP_SEND_EOF);
FALLTHROUGH();
case SSH_SESSION_DISCONNECT:
- /* during weird times when we have been prematurely aborted, the channel
- is still alive when we reach this state and we MUST kill the channel
- properly first */
- if(sshc->scp_session) {
- ssh_scp_free(sshc->scp_session);
- sshc->scp_session = NULL;
- }
-
- if(sshc->sftp_file) {
- sftp_close(sshc->sftp_file);
- sshc->sftp_file = NULL;
- }
- if(sshc->sftp_session) {
- sftp_free(sshc->sftp_session);
- sshc->sftp_session = NULL;
- }
-
- ssh_disconnect(sshc->ssh_session);
- if(!ssh_version(SSH_VERSION_INT(0, 10, 0))) {
- /* conn->sock[FIRSTSOCKET] is closed by ssh_disconnect behind our back,
- tell the connection to forget about it. This libssh
- bug is fixed in 0.10.0. */
- conn_forget_socket(data, FIRSTSOCKET);
- }
-
- SSH_STRING_FREE_CHAR(sshc->homedir);
-
- myssh_to(data, sshc, SSH_SESSION_FREE);
+ myssh_SESSION_DISCONNECT(data, sshc);
FALLTHROUGH();
case SSH_SESSION_FREE:
sshc_cleanup(sshc);
/* the code we are about to return */
result = sshc->actualcode;
memset(sshc, 0, sizeof(struct ssh_conn));
- connclose(conn, "SSH session free");
+ connclose(data->conn, "SSH session free");
sshc->state = SSH_SESSION_FREE; /* current */
sshc->nextstate = SSH_NO_STATE;
myssh_to(data, sshc, SSH_STOP);