aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssh.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssh.c')
-rw-r--r--lib/ssh.c124
1 files changed, 88 insertions, 36 deletions
diff --git a/lib/ssh.c b/lib/ssh.c
index ff5994b4..314d8984 100644
--- a/lib/ssh.c
+++ b/lib/ssh.c
@@ -486,6 +486,17 @@ static int sshkeycallback(CURL *easy,
#endif
/*
+ * Earlier libssh2 versions didn't do SCP properly beyond 32bit sizes on 32bit
+ * architectures so we check of the necessary function is present.
+ */
+#ifndef HAVE_LIBSSH2_SCP_SEND64
+#define SCP_SEND(a,b,c,d) libssh2_scp_send_ex(a, b, (int)(c), (size_t)d, 0, 0)
+#else
+#define SCP_SEND(a,b,c,d) libssh2_scp_send64(a, b, (int)(c), \
+ (libssh2_uint64_t)d, 0, 0)
+#endif
+
+/*
* 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
@@ -1431,6 +1442,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
data->state.resume_from = 0;
}
else {
+ curl_off_t size = attrs.filesize;
+ if(size < 0) {
+ failf(data, "Bad file size (%" FORMAT_OFF_T ")", size);
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
data->state.resume_from = attrs.filesize;
}
}
@@ -1556,8 +1572,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
Curl_pgrsSetUploadSize(data, data->set.infilesize);
}
/* upload data */
- result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL,
- FIRSTSOCKET, NULL);
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
/* not set by Curl_setup_transfer to preserve keepon bits */
conn->sockfd = conn->writesockfd;
@@ -1850,7 +1865,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
sshc->readdir_longentry = NULL;
/* no data to transfer */
- result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
state(conn, SSH_STOP);
break;
@@ -1901,16 +1916,19 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
data->req.maxdownload = -1;
}
else {
- curl_off_t size;
+ curl_off_t size = attrs.filesize;
- size = attrs.filesize;
+ if(size < 0) {
+ failf(data, "Bad file size (%" FORMAT_OFF_T ")", size);
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
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=='-')))
+ while(*ptr && (isspace((int)*ptr) || (*ptr=='-')))
ptr++;
to=curlx_strtoofft(ptr, &ptr2, 0);
if((ptr == ptr2) /* no "to" value given */
@@ -1975,14 +1993,14 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
/* Setup the actual download */
if(data->req.size == 0) {
/* no data to transfer */
- result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ 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);
+ 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;
@@ -2084,9 +2102,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
* directory in the path.
*/
sshc->ssh_channel =
- libssh2_scp_send_ex(sshc->ssh_session, sftp_scp->path,
- (int)(data->set.new_file_perms),
- (size_t)data->set.infilesize, 0, 0);
+ SCP_SEND(sshc->ssh_session, sftp_scp->path, data->set.new_file_perms,
+ data->set.infilesize);
if(!sshc->ssh_channel) {
if(libssh2_session_last_errno(sshc->ssh_session) ==
LIBSSH2_ERROR_EAGAIN) {
@@ -2107,8 +2124,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
}
/* upload data */
- result = Curl_setup_transfer(conn, -1, data->req.size, FALSE, NULL,
- FIRSTSOCKET, NULL);
+ Curl_setup_transfer(conn, -1, data->req.size, FALSE, NULL,
+ FIRSTSOCKET, NULL);
/* not set by Curl_setup_transfer to preserve keepon bits */
conn->sockfd = conn->writesockfd;
@@ -2159,8 +2176,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
/* 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);
+ Curl_setup_transfer(conn, FIRSTSOCKET, bytecount, FALSE, NULL, -1, NULL);
/* not set by Curl_setup_transfer to preserve keepon bits */
conn->writesockfd = conn->sockfd;
@@ -2410,15 +2426,28 @@ static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done)
return result;
}
-static CURLcode ssh_easy_statemach(struct connectdata *conn)
+static CURLcode ssh_easy_statemach(struct connectdata *conn,
+ bool duringconnect)
{
struct ssh_conn *sshc = &conn->proto.sshc;
CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
while((sshc->state != SSH_STOP) && !result) {
bool block;
+ long left;
+
result = ssh_statemach_act(conn, &block);
+ if(Curl_pgrsUpdate(conn))
+ return CURLE_ABORTED_BY_CALLBACK;
+
+ left = Curl_timeleft(conn, NULL, duringconnect);
+ if(left < 0) {
+ failf(data, "Operation timed out\n");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
#ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
if((CURLE_OK == result) && block) {
int dir = libssh2_session_block_directions(sshc->ssh_session);
@@ -2432,7 +2461,8 @@ static CURLcode ssh_easy_statemach(struct connectdata *conn)
fd_write = sock;
}
/* wait for the socket to become ready */
- Curl_socket_ready(fd_read, fd_write, 1000); /* ignore result */
+ Curl_socket_ready(fd_read, fd_write,
+ (int)(left>1000?1000:left)); /* ignore result */
}
#endif
@@ -2466,6 +2496,9 @@ static CURLcode ssh_init(struct connectdata *conn)
return CURLE_OK;
}
+static Curl_recv scp_recv, sftp_recv;
+static Curl_send scp_send, sftp_send;
+
/*
* Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
* do protocol-specific actions at connect-time.
@@ -2491,6 +2524,13 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done)
if(result)
return result;
+ if(conn->protocol & PROT_SCP) {
+ conn->recv[FIRSTSOCKET] = scp_recv;
+ conn->send[FIRSTSOCKET] = scp_send;
+ } else {
+ conn->recv[FIRSTSOCKET] = sftp_recv;
+ conn->send[FIRSTSOCKET] = sftp_send;
+ }
ssh = &conn->proto.sshc;
#ifdef CURL_LIBSSH2_DEBUG
@@ -2540,7 +2580,7 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done)
if(data->state.used_interface == Curl_if_multi)
result = ssh_multi_statemach(conn, done);
else {
- result = ssh_easy_statemach(conn);
+ result = ssh_easy_statemach(conn, TRUE);
if(!result)
*done = TRUE;
}
@@ -2576,7 +2616,7 @@ CURLcode scp_perform(struct connectdata *conn,
result = ssh_multi_statemach(conn, dophase_done);
}
else {
- result = ssh_easy_statemach(conn);
+ result = ssh_easy_statemach(conn, FALSE);
*dophase_done = TRUE; /* with the easy interface we are done here */
}
*connected = conn->bits.tcpconnect;
@@ -2657,7 +2697,7 @@ static CURLcode scp_disconnect(struct connectdata *conn)
state(conn, SSH_SESSION_DISCONNECT);
- result = ssh_easy_statemach(conn);
+ result = ssh_easy_statemach(conn, FALSE);
}
return result;
@@ -2678,7 +2718,7 @@ static CURLcode ssh_done(struct connectdata *conn, CURLcode status)
non-blocking DONE operations, not in the multi state machine and with
Curl_done() invokes on several places in the code!
*/
- result = ssh_easy_statemach(conn);
+ result = ssh_easy_statemach(conn, FALSE);
}
else
result = status;
@@ -2705,8 +2745,8 @@ static CURLcode scp_done(struct connectdata *conn, CURLcode status,
}
/* return number of received (decrypted) bytes */
-ssize_t Curl_scp_send(struct connectdata *conn, int sockindex,
- const void *mem, size_t len)
+static ssize_t scp_send(struct connectdata *conn, int sockindex,
+ const void *mem, size_t len, CURLcode *err)
{
ssize_t nwrite;
(void)sockindex; /* we only support SCP on the fixed known primary socket */
@@ -2717,8 +2757,10 @@ ssize_t Curl_scp_send(struct connectdata *conn, int sockindex,
ssh_block2waitfor(conn, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
- if(nwrite == LIBSSH2_ERROR_EAGAIN)
- return 0;
+ if(nwrite == LIBSSH2_ERROR_EAGAIN) {
+ *err = CURLE_AGAIN;
+ nwrite = 0;
+ }
return nwrite;
}
@@ -2727,8 +2769,8 @@ ssize_t Curl_scp_send(struct connectdata *conn, int sockindex,
* If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
* a regular CURLcode value.
*/
-ssize_t Curl_scp_recv(struct connectdata *conn, int sockindex,
- char *mem, size_t len)
+static ssize_t scp_recv(struct connectdata *conn, int sockindex,
+ char *mem, size_t len, CURLcode *err)
{
ssize_t nread;
(void)sockindex; /* we only support SCP on the fixed known primary socket */
@@ -2738,6 +2780,10 @@ ssize_t Curl_scp_recv(struct connectdata *conn, int sockindex,
libssh2_channel_read(conn->proto.sshc.ssh_channel, mem, len);
ssh_block2waitfor(conn, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+ if (nread == LIBSSH2_ERROR_EAGAIN) {
+ *err = CURLE_AGAIN;
+ nread = -1;
+ }
return nread;
}
@@ -2774,7 +2820,7 @@ CURLcode sftp_perform(struct connectdata *conn,
result = ssh_multi_statemach(conn, dophase_done);
}
else {
- result = ssh_easy_statemach(conn);
+ result = ssh_easy_statemach(conn, FALSE);
*dophase_done = TRUE; /* with the easy interface we are done here */
}
*connected = conn->bits.tcpconnect;
@@ -2814,7 +2860,7 @@ static CURLcode sftp_disconnect(struct connectdata *conn)
if(conn->proto.sshc.ssh_session) {
/* only if there's a session still around to use! */
state(conn, SSH_SFTP_SHUTDOWN);
- result = ssh_easy_statemach(conn);
+ result = ssh_easy_statemach(conn, FALSE);
}
DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n"));
@@ -2842,8 +2888,8 @@ static CURLcode sftp_done(struct connectdata *conn, CURLcode status,
}
/* return number of sent bytes */
-ssize_t Curl_sftp_send(struct connectdata *conn, int sockindex,
- const void *mem, size_t len)
+static ssize_t sftp_send(struct connectdata *conn, int sockindex,
+ const void *mem, size_t len, CURLcode *err)
{
ssize_t nwrite; /* libssh2_sftp_write() used to return size_t in 0.14
but is changed to ssize_t in 0.15. These days we don't
@@ -2854,8 +2900,10 @@ ssize_t Curl_sftp_send(struct connectdata *conn, int sockindex,
ssh_block2waitfor(conn, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
- if(nwrite == LIBSSH2_ERROR_EAGAIN)
- return 0;
+ if(nwrite == LIBSSH2_ERROR_EAGAIN) {
+ *err = CURLE_AGAIN;
+ nwrite = 0;
+ }
return nwrite;
}
@@ -2863,8 +2911,8 @@ ssize_t Curl_sftp_send(struct connectdata *conn, int sockindex,
/*
* Return number of received (decrypted) bytes
*/
-ssize_t Curl_sftp_recv(struct connectdata *conn, int sockindex,
- char *mem, size_t len)
+static ssize_t sftp_recv(struct connectdata *conn, int sockindex,
+ char *mem, size_t len, CURLcode *err)
{
ssize_t nread;
(void)sockindex;
@@ -2873,6 +2921,10 @@ ssize_t Curl_sftp_recv(struct connectdata *conn, int sockindex,
ssh_block2waitfor(conn, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+ if(nread == LIBSSH2_ERROR_EAGAIN) {
+ *err = CURLE_AGAIN;
+ nread = -1;
+ }
return nread;
}