mirror of
https://github.com/moparisthebest/curl
synced 2024-12-22 08:08:50 -05:00
* Updates for the latest version of libssh2, specifically
libssh2_sftp_shutdown() and libssh2_session_free() can now return LIBSSH2_ERROR_EAGAIN. * Fix the _send() and _recv() return values so non-blocking works
This commit is contained in:
parent
6f59e19b91
commit
ab7e7144ef
194
lib/ssh.c
194
lib/ssh.c
@ -258,6 +258,8 @@ static void state(struct connectdata *conn, ftpstate state)
|
|||||||
"SSH_SFTP_INIT",
|
"SSH_SFTP_INIT",
|
||||||
"SSH_SFTP_REALPATH",
|
"SSH_SFTP_REALPATH",
|
||||||
"SSH_GET_WORKINGPATH",
|
"SSH_GET_WORKINGPATH",
|
||||||
|
"SSH_SFTP_SHUTDOWN",
|
||||||
|
"SSH_SESSION_FREE",
|
||||||
"QUIT"
|
"QUIT"
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
@ -295,10 +297,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
|
|||||||
}
|
}
|
||||||
else if (rc) {
|
else if (rc) {
|
||||||
failf(data, "Failure establishing ssh session");
|
failf(data, "Failure establishing ssh session");
|
||||||
libssh2_session_free(ssh->ssh_session);
|
state(conn, SSH_SESSION_FREE);
|
||||||
ssh->ssh_session = NULL;
|
sshc->actualCode = CURLE_FAILED_INIT;
|
||||||
state(conn, SSH_STOP);
|
|
||||||
result = CURLE_FAILED_INIT;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,10 +347,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
|
|||||||
LIBSSH2_ERROR_EAGAIN) {
|
LIBSSH2_ERROR_EAGAIN) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
libssh2_session_free(ssh->ssh_session);
|
state(conn, SSH_SESSION_FREE);
|
||||||
ssh->ssh_session = NULL;
|
sshc->actualCode = CURLE_OUT_OF_MEMORY;
|
||||||
state(conn, SSH_STOP);
|
|
||||||
result = CURLE_OUT_OF_MEMORY;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -491,10 +489,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
|
|||||||
case SSH_AUTH_DONE:
|
case SSH_AUTH_DONE:
|
||||||
if (!sshc->authed) {
|
if (!sshc->authed) {
|
||||||
failf(data, "Authentication failure");
|
failf(data, "Authentication failure");
|
||||||
libssh2_session_free(ssh->ssh_session);
|
state(conn, SSH_SESSION_FREE);
|
||||||
ssh->ssh_session = NULL;
|
sshc->actualCode = CURLE_LOGIN_DENIED;
|
||||||
state(conn, SSH_STOP);
|
|
||||||
result = CURLE_LOGIN_DENIED;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -524,10 +520,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
|
|||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
failf(data, "Failure initialising sftp session\n");
|
failf(data, "Failure initialising sftp session\n");
|
||||||
libssh2_session_free(ssh->ssh_session);
|
state(conn, SSH_SESSION_FREE);
|
||||||
ssh->ssh_session = NULL;
|
sshc->actualCode = CURLE_FAILED_INIT;
|
||||||
state(conn, SSH_STOP);
|
|
||||||
result = CURLE_FAILED_INIT;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -551,12 +545,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
|
|||||||
tempHome[rc] = '\0';
|
tempHome[rc] = '\0';
|
||||||
ssh->homedir = (char *)strdup(tempHome);
|
ssh->homedir = (char *)strdup(tempHome);
|
||||||
if (!ssh->homedir) {
|
if (!ssh->homedir) {
|
||||||
libssh2_sftp_shutdown(ssh->sftp_session);
|
state(conn, SSH_SFTP_SHUTDOWN);
|
||||||
ssh->sftp_session = NULL;
|
sshc->actualCode = CURLE_OUT_OF_MEMORY;
|
||||||
libssh2_session_free(ssh->ssh_session);
|
|
||||||
ssh->ssh_session = NULL;
|
|
||||||
state(conn, SSH_STOP);
|
|
||||||
result = CURLE_OUT_OF_MEMORY;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -588,11 +578,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
|
|||||||
if (conn->protocol == PROT_SCP) {
|
if (conn->protocol == PROT_SCP) {
|
||||||
real_path = (char *)malloc(working_path_len+1);
|
real_path = (char *)malloc(working_path_len+1);
|
||||||
if (real_path == NULL) {
|
if (real_path == NULL) {
|
||||||
libssh2_session_free(ssh->ssh_session);
|
|
||||||
ssh->ssh_session = NULL;
|
|
||||||
Curl_safefree(working_path);
|
Curl_safefree(working_path);
|
||||||
state(conn, SSH_STOP);
|
state(conn, SSH_SESSION_FREE);
|
||||||
result = CURLE_OUT_OF_MEMORY;
|
sshc->actualCode = CURLE_OUT_OF_MEMORY;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (working_path[1] == '~')
|
if (working_path[1] == '~')
|
||||||
@ -607,15 +595,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
|
|||||||
real_path = (char *)malloc(strlen(ssh->homedir) +
|
real_path = (char *)malloc(strlen(ssh->homedir) +
|
||||||
working_path_len + 1);
|
working_path_len + 1);
|
||||||
if (real_path == NULL) {
|
if (real_path == NULL) {
|
||||||
libssh2_sftp_shutdown(ssh->sftp_session);
|
|
||||||
ssh->sftp_session = NULL;
|
|
||||||
libssh2_session_free(ssh->ssh_session);
|
|
||||||
ssh->ssh_session = NULL;
|
|
||||||
Curl_safefree(ssh->homedir);
|
Curl_safefree(ssh->homedir);
|
||||||
ssh->homedir = NULL;
|
ssh->homedir = NULL;
|
||||||
Curl_safefree(working_path);
|
Curl_safefree(working_path);
|
||||||
state(conn, SSH_STOP);
|
state(conn, SSH_SFTP_SHUTDOWN);
|
||||||
result = CURLE_OUT_OF_MEMORY;
|
sshc->actualCode = CURLE_OUT_OF_MEMORY;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* It is referenced to the home directory, so strip the
|
/* It is referenced to the home directory, so strip the
|
||||||
@ -631,47 +615,50 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
|
|||||||
else {
|
else {
|
||||||
real_path = (char *)malloc(working_path_len+1);
|
real_path = (char *)malloc(working_path_len+1);
|
||||||
if (real_path == NULL) {
|
if (real_path == NULL) {
|
||||||
libssh2_sftp_shutdown(ssh->sftp_session);
|
|
||||||
ssh->sftp_session = NULL;
|
|
||||||
libssh2_session_free(ssh->ssh_session);
|
|
||||||
ssh->ssh_session = NULL;
|
|
||||||
Curl_safefree(ssh->homedir);
|
Curl_safefree(ssh->homedir);
|
||||||
ssh->homedir = NULL;
|
ssh->homedir = NULL;
|
||||||
Curl_safefree(working_path);
|
Curl_safefree(working_path);
|
||||||
state(conn, SSH_STOP);
|
state(conn, SSH_SFTP_SHUTDOWN);
|
||||||
result = CURLE_OUT_OF_MEMORY;
|
sshc->actualCode = CURLE_OUT_OF_MEMORY;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
memcpy(real_path, working_path, 1+working_path_len);
|
memcpy(real_path, working_path, 1+working_path_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
libssh2_session_free(ssh->ssh_session);
|
|
||||||
ssh->ssh_session = NULL;
|
|
||||||
Curl_safefree(working_path);
|
Curl_safefree(working_path);
|
||||||
state(conn, SSH_STOP);
|
state(conn, SSH_SESSION_FREE);
|
||||||
result = CURLE_FAILED_INIT;
|
sshc->actualCode = CURLE_FAILED_INIT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Curl_safefree(working_path);
|
Curl_safefree(working_path);
|
||||||
ssh->path = real_path;
|
ssh->path = real_path;
|
||||||
|
|
||||||
/*
|
|
||||||
*****************************************
|
|
||||||
*****************************************
|
|
||||||
** TEMPORARY **
|
|
||||||
*****************************************
|
|
||||||
*****************************************
|
|
||||||
*/
|
|
||||||
/* Set libssh2 to non-blocking, since cURL is all non-blocking */
|
|
||||||
libssh2_session_set_blocking(ssh->ssh_session, 1);
|
|
||||||
|
|
||||||
/* Connect is all done */
|
/* Connect is all done */
|
||||||
state(conn, SSH_STOP);
|
state(conn, SSH_STOP);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SSH_SFTP_SHUTDOWN:
|
||||||
|
rc = libssh2_sftp_shutdown(ssh->sftp_session);
|
||||||
|
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ssh->sftp_session = NULL;
|
||||||
|
state(conn, SSH_SESSION_FREE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSH_SESSION_FREE:
|
||||||
|
rc = libssh2_session_free(ssh->ssh_session);
|
||||||
|
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ssh->ssh_session = NULL;
|
||||||
|
state(conn, SSH_STOP);
|
||||||
|
result = sshc->actualCode;
|
||||||
|
break;
|
||||||
|
|
||||||
case SSH_QUIT:
|
case SSH_QUIT:
|
||||||
/* fallthrough, just stop! */
|
/* fallthrough, just stop! */
|
||||||
default:
|
default:
|
||||||
@ -1277,6 +1264,11 @@ ssize_t Curl_scp_send(struct connectdata *conn, int sockindex,
|
|||||||
nwrite = (ssize_t)
|
nwrite = (ssize_t)
|
||||||
libssh2_channel_write(conn->data->reqdata.proto.ssh->ssh_channel,
|
libssh2_channel_write(conn->data->reqdata.proto.ssh->ssh_channel,
|
||||||
mem, len);
|
mem, len);
|
||||||
|
#if (LIBSSH2_APINO >= 200706012030)
|
||||||
|
if (nwrite == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
(void)sockindex;
|
(void)sockindex;
|
||||||
return nwrite;
|
return nwrite;
|
||||||
@ -1710,9 +1702,17 @@ CURLcode Curl_sftp_done(struct connectdata *conn, CURLcode status,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sftp->sftp_session) {
|
if (sftp->sftp_session) {
|
||||||
|
#if (LIBSSH2_APINO >= 200706012030)
|
||||||
|
while ((ret = libssh2_sftp_shutdown(sftp->sftp_session)) ==
|
||||||
|
LIBSSH2_ERROR_EAGAIN);
|
||||||
|
if (ret < 0) {
|
||||||
|
infof(conn->data, "Failed to stop libssh2 sftp subsystem\n");
|
||||||
|
}
|
||||||
|
#else /* !(LIBSSH2_APINO >= 200706012030) */
|
||||||
if (libssh2_sftp_shutdown(sftp->sftp_session) < 0) {
|
if (libssh2_sftp_shutdown(sftp->sftp_session) < 0) {
|
||||||
infof(conn->data, "Failed to stop libssh2 sftp subsystem\n");
|
infof(conn->data, "Failed to stop libssh2 sftp subsystem\n");
|
||||||
}
|
}
|
||||||
|
#endif /* !(LIBSSH2_APINO >= 200706012030) */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sftp->ssh_channel) {
|
if (sftp->ssh_channel) {
|
||||||
@ -1764,11 +1764,39 @@ ssize_t Curl_sftp_send(struct connectdata *conn, int sockindex,
|
|||||||
#else
|
#else
|
||||||
nwrite = (ssize_t)
|
nwrite = (ssize_t)
|
||||||
libssh2_sftp_write(conn->data->reqdata.proto.ssh->sftp_handle, mem, len);
|
libssh2_sftp_write(conn->data->reqdata.proto.ssh->sftp_handle, mem, len);
|
||||||
|
#if (LIBSSH2_APINO >= 200706012030)
|
||||||
|
if (nwrite == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
(void)sockindex;
|
(void)sockindex;
|
||||||
return nwrite;
|
return nwrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
|
||||||
|
* a regular CURLcode value.
|
||||||
|
*/
|
||||||
|
ssize_t Curl_sftp_recv(struct connectdata *conn, int sockindex,
|
||||||
|
char *mem, size_t len)
|
||||||
|
{
|
||||||
|
ssize_t nread;
|
||||||
|
(void)sockindex;
|
||||||
|
|
||||||
|
/* libssh2_sftp_read() returns size_t !*/
|
||||||
|
|
||||||
|
#if defined(LIBSSH2SFTP_EAGAIN) && (LIBSSH2_APINO < 200706012030)
|
||||||
|
/* we prefer the non-blocking API but that didn't exist previously */
|
||||||
|
nread = (ssize_t)
|
||||||
|
libssh2_sftp_readnb(conn->data->reqdata.proto.ssh->sftp_handle, mem, len);
|
||||||
|
#else
|
||||||
|
nread = (ssize_t)
|
||||||
|
libssh2_sftp_read(conn->data->reqdata.proto.ssh->sftp_handle, mem, len);
|
||||||
|
#endif
|
||||||
|
return nread;
|
||||||
|
}
|
||||||
|
|
||||||
/* The get_pathname() function is being borrowed from OpenSSH sftp.c
|
/* The get_pathname() function is being borrowed from OpenSSH sftp.c
|
||||||
version 4.6p1. */
|
version 4.6p1. */
|
||||||
/*
|
/*
|
||||||
@ -2188,28 +2216,54 @@ static CURLcode sftp_sendquote(struct connectdata *conn,
|
|||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
|
* Create the path sftp->path on the remote site
|
||||||
* a regular CURLcode value.
|
* returns CURL_OK on success, -1 on failure
|
||||||
*/
|
*/
|
||||||
ssize_t Curl_sftp_recv(struct connectdata *conn, int sockindex,
|
static CURLcode sftp_create_dirs(struct connectdata *conn) {
|
||||||
char *mem, size_t len)
|
CURLcode result = CURLE_OK;
|
||||||
{
|
unsigned int sftp_err = 0;
|
||||||
ssize_t nread;
|
int rc;
|
||||||
(void)sockindex;
|
struct SSHPROTO *sftp = conn->data->reqdata.proto.ssh;
|
||||||
|
|
||||||
/* libssh2_sftp_read() returns size_t !*/
|
if (strlen(sftp->path) > 1) {
|
||||||
|
char *slash_pos = sftp->path + 1; /* ignore the leading '/' */
|
||||||
|
|
||||||
#if defined(LIBSSH2SFTP_EAGAIN) && (LIBSSH2_APINO < 200706012030)
|
while ((slash_pos = strchr(slash_pos, '/')) != NULL) {
|
||||||
/* we prefer the non-blocking API but that didn't exist previously */
|
*slash_pos = 0;
|
||||||
nread = (ssize_t)
|
|
||||||
libssh2_sftp_readnb(conn->data->reqdata.proto.ssh->sftp_handle, mem, len);
|
infof(conn->data, "Creating directory '%s'\n", sftp->path);
|
||||||
#else
|
/* 'mode' - parameter is preliminary - default to 0644 */
|
||||||
nread = (ssize_t)
|
#if (LIBSSH2_APINO >= 200706012030)
|
||||||
libssh2_sftp_read(conn->data->reqdata.proto.ssh->sftp_handle, mem, len);
|
while ((rc = libssh2_sftp_mkdir(sftp->sftp_session, sftp->path,
|
||||||
#endif
|
LIBSSH2_SFTP_S_IRWXU |
|
||||||
return nread;
|
LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IXGRP |
|
||||||
|
LIBSSH2_SFTP_S_IROTH | LIBSSH2_SFTP_S_IXOTH)) ==
|
||||||
|
LIBSSH2_ERROR_EAGAIN);
|
||||||
|
#else /* !(LIBSSH2_APINO >= 200706012030) */
|
||||||
|
rc = libssh2_sftp_mkdir(sftp->sftp_session, sftp->path,
|
||||||
|
LIBSSH2_SFTP_S_IRWXU |
|
||||||
|
LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IXGRP |
|
||||||
|
LIBSSH2_SFTP_S_IROTH | LIBSSH2_SFTP_S_IXOTH);
|
||||||
|
#endif /* !(LIBSSH2_APINO >= 200706012030) */
|
||||||
|
*slash_pos = '/';
|
||||||
|
++slash_pos;
|
||||||
|
if (rc == -1) {
|
||||||
|
/* 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(sftp->sftp_session);
|
||||||
|
if ((sftp_err != LIBSSH2_FX_FILE_ALREADY_EXISTS) &&
|
||||||
|
(sftp_err != LIBSSH2_FX_FAILURE) &&
|
||||||
|
(sftp_err != LIBSSH2_FX_PERMISSION_DENIED)) {
|
||||||
|
result = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* USE_LIBSSH2 */
|
#endif /* USE_LIBSSH2 */
|
||||||
|
@ -425,6 +425,8 @@ typedef enum {
|
|||||||
SSH_SFTP_INIT,
|
SSH_SFTP_INIT,
|
||||||
SSH_SFTP_REALPATH,
|
SSH_SFTP_REALPATH,
|
||||||
SSH_GET_WORKINGPATH,
|
SSH_GET_WORKINGPATH,
|
||||||
|
SSH_SFTP_SHUTDOWN,
|
||||||
|
SSH_SESSION_FREE,
|
||||||
SSH_QUIT,
|
SSH_QUIT,
|
||||||
SSH_LAST /* never used */
|
SSH_LAST /* never used */
|
||||||
} sshstate;
|
} sshstate;
|
||||||
@ -453,6 +455,7 @@ struct ssh_conn {
|
|||||||
char rsa[PATH_MAX];
|
char rsa[PATH_MAX];
|
||||||
bool authed;
|
bool authed;
|
||||||
sshstate state; /* always use ssh.c:state() to change state! */
|
sshstate state; /* always use ssh.c:state() to change state! */
|
||||||
|
CURLcode actualCode; /* the actual error code */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user