points to data it needs. */
union {
struct FILEPROTO *file;
- struct SSHPROTO *ssh;
} p;
#ifndef CURL_DISABLE_COOKIES
unsigned char setcookies;
static bool ssh_config_matches(struct connectdata *one,
struct connectdata *two)
{
- return Curl_safecmp(one->proto.sshc.rsa, two->proto.sshc.rsa) &&
- Curl_safecmp(one->proto.sshc.rsa_pub, two->proto.sshc.rsa_pub);
+ struct ssh_conn *sshc1, *sshc2;
+
+ sshc1 = Curl_conn_meta_get(one, CURL_META_SSH_CONN);
+ sshc2 = Curl_conn_meta_get(two, CURL_META_SSH_CONN);
+ return (sshc1 && sshc2 && Curl_safecmp(sshc1->rsa, sshc2->rsa) &&
+ Curl_safecmp(sshc1->rsa_pub, sshc2->rsa_pub));
}
#endif
struct negotiatedata proxyneg; /* state data for proxy Negotiate auth */
#endif
- union {
-#ifdef USE_SSH
- struct ssh_conn sshc;
-#endif
- unsigned int unused:1; /* avoids empty union */
- } proto;
-
#ifdef USE_UNIX_SOCKETS
char *unix_domain_socket;
#endif
bool *connected,
bool *dophase_done);
-static void sftp_quote(struct Curl_easy *data);
-static void sftp_quote_stat(struct Curl_easy *data);
+static void sftp_quote(struct Curl_easy *data,
+ struct ssh_conn *sshc,
+ struct SSHPROTO *sshp);
+static void sftp_quote_stat(struct Curl_easy *data, struct ssh_conn *sshc);
static int myssh_getsock(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *sock);
-static void myssh_block2waitfor(struct connectdata *conn, bool block);
+static void myssh_block2waitfor(struct connectdata *conn,
+ struct ssh_conn *sshc,
+ bool block);
static CURLcode myssh_setup_connection(struct Curl_easy *data,
struct connectdata *conn);
-static void sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data);
+static void sshc_cleanup(struct ssh_conn *sshc);
/*
* SCP protocol handler.
}
#ifndef DEBUGBUILD
-#define state(x,y) mystate(x,y)
+#define myssh_state(x,y,z) myssh_set_state(x,y,z)
#else
-#define state(x,y) mystate(x,y, __LINE__)
+#define myssh_state(x,y,z) myssh_set_state(x,y,z, __LINE__)
#endif
/*
* SSH State machine related code
*/
/* This is the ONLY way to change SSH state! */
-static void mystate(struct Curl_easy *data, sshstate nowstate
+static void myssh_set_state(struct Curl_easy *data,
+ struct ssh_conn *sshc,
+ sshstate nowstate
#ifdef DEBUGBUILD
- , int lineno
+ , int lineno
#endif
)
{
- struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
/* for debug purposes */
static const char *const names[] = {
lineno);
}
#endif
-
+ (void)data;
sshc->state = nowstate;
}
*
* Returns SSH_OK or SSH_ERROR.
*/
-static int myssh_is_known(struct Curl_easy *data)
+static int myssh_is_known(struct Curl_easy *data, struct ssh_conn *sshc)
{
int rc;
- struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
ssh_key pubkey;
size_t hlen;
unsigned char *hash = NULL;
return rc;
}
-#define MOVE_TO_ERROR_STATE(_r) do { \
- state(data, SSH_SESSION_DISCONNECT); \
- sshc->actualcode = _r; \
- rc = SSH_ERROR; \
+#define MOVE_TO_ERROR_STATE(_r) do { \
+ myssh_state(data, sshc, SSH_SESSION_DISCONNECT); \
+ sshc->actualcode = _r; \
+ rc = SSH_ERROR; \
} while(0)
#define MOVE_TO_SFTP_CLOSE_STATE() do { \
- state(data, SSH_SFTP_CLOSE); \
+ myssh_state(data, sshc, SSH_SFTP_CLOSE); \
sshc->actualcode = \
sftp_error_to_CURLE(sftp_get_error(sshc->sftp_session)); \
rc = SSH_ERROR; \
#define MOVE_TO_PASSWD_AUTH do { \
if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { \
rc = SSH_OK; \
- state(data, SSH_AUTH_PASS_INIT); \
+ myssh_state(data, sshc, SSH_AUTH_PASS_INIT); \
} \
else { \
MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); \
#define MOVE_TO_KEY_AUTH do { \
if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { \
rc = SSH_OK; \
- state(data, SSH_AUTH_KEY_INIT); \
+ myssh_state(data, sshc, SSH_AUTH_KEY_INIT); \
} \
else { \
MOVE_TO_PASSWD_AUTH; \
#define MOVE_TO_GSSAPI_AUTH do { \
if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) { \
rc = SSH_OK; \
- state(data, SSH_AUTH_GSSAPI); \
+ myssh_state(data, sshc, SSH_AUTH_GSSAPI); \
} \
else { \
MOVE_TO_KEY_AUTH; \
} while(0)
static
-int myssh_auth_interactive(struct connectdata *conn)
+int myssh_auth_interactive(struct connectdata *conn,
+ struct ssh_conn *sshc)
{
int rc;
- struct ssh_conn *sshc = &conn->proto.sshc;
int nprompts;
restart:
* to will be set to TRUE if the libssh function returns SSH_AGAIN
* meaning it wants to be called again when the socket is ready
*/
-static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
+static CURLcode myssh_statemach_act(struct Curl_easy *data,
+ struct ssh_conn *sshc,
+ struct SSHPROTO *sshp,
+ bool *block)
{
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
- struct SSHPROTO *protop = data->req.p.ssh;
- struct ssh_conn *sshc = &conn->proto.sshc;
curl_socket_t sock = conn->sock[FIRSTSOCKET];
int rc = SSH_NO_ERROR, err;
int seekerr = CURL_SEEKFUNC_OK;
non-blocking */
ssh_set_blocking(sshc->ssh_session, 0);
- state(data, SSH_S_STARTUP);
+ myssh_state(data, sshc, SSH_S_STARTUP);
FALLTHROUGH();
case SSH_S_STARTUP:
rc = ssh_connect(sshc->ssh_session);
- myssh_block2waitfor(conn, (rc == SSH_AGAIN));
+ myssh_block2waitfor(conn, sshc, (rc == SSH_AGAIN));
if(rc == SSH_AGAIN) {
DEBUGF(infof(data, "ssh_connect -> EAGAIN"));
break;
break;
}
- state(data, SSH_HOSTKEY);
+ myssh_state(data, sshc, SSH_HOSTKEY);
FALLTHROUGH();
case SSH_HOSTKEY:
- rc = myssh_is_known(data);
+ rc = myssh_is_known(data, sshc);
if(rc != SSH_OK) {
MOVE_TO_ERROR_STATE(CURLE_PEER_FAILED_VERIFICATION);
break;
}
- state(data, SSH_AUTHLIST);
+ myssh_state(data, sshc, SSH_AUTHLIST);
FALLTHROUGH();
case SSH_AUTHLIST:{
sshc->authed = FALSE;
if(rc == SSH_AUTH_SUCCESS) {
sshc->authed = TRUE;
infof(data, "Authenticated with none");
- state(data, SSH_AUTH_DONE);
+ myssh_state(data, sshc, SSH_AUTH_DONE);
break;
}
else if(rc == SSH_AUTH_ERROR) {
sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD ?
"password": "");
if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) {
- state(data, SSH_AUTH_PKEY_INIT);
+ myssh_state(data, sshc, SSH_AUTH_PKEY_INIT);
infof(data, "Authentication using SSH public key file");
}
else if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) {
- state(data, SSH_AUTH_GSSAPI);
+ myssh_state(data, sshc, SSH_AUTH_GSSAPI);
}
else if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {
- state(data, SSH_AUTH_KEY_INIT);
+ myssh_state(data, sshc, SSH_AUTH_KEY_INIT);
}
else if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) {
- state(data, SSH_AUTH_PASS_INIT);
+ myssh_state(data, sshc, SSH_AUTH_PASS_INIT);
}
else { /* unsupported authentication method */
MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
break;
}
- state(data, SSH_AUTH_PKEY);
+ myssh_state(data, sshc, SSH_AUTH_PKEY);
break;
}
rc = SSH_OK;
sshc->authed = TRUE;
infof(data, "Completed public key authentication");
- state(data, SSH_AUTH_DONE);
+ myssh_state(data, sshc, SSH_AUTH_DONE);
break;
}
if(rc == SSH_AUTH_SUCCESS) {
sshc->authed = TRUE;
infof(data, "Completed public key authentication");
- state(data, SSH_AUTH_DONE);
+ myssh_state(data, sshc, SSH_AUTH_DONE);
break;
}
else {
rc = SSH_OK;
sshc->authed = TRUE;
infof(data, "Completed gssapi authentication");
- state(data, SSH_AUTH_DONE);
+ myssh_state(data, sshc, SSH_AUTH_DONE);
break;
}
case SSH_AUTH_KEY_INIT:
if(data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) {
- state(data, SSH_AUTH_KEY);
+ myssh_state(data, sshc, SSH_AUTH_KEY);
}
else {
MOVE_TO_PASSWD_AUTH;
case SSH_AUTH_KEY:
/* keyboard-interactive authentication */
- rc = myssh_auth_interactive(conn);
+ rc = myssh_auth_interactive(conn, sshc);
if(rc == SSH_AGAIN) {
break;
}
if(rc == SSH_OK) {
sshc->authed = TRUE;
infof(data, "completed keyboard interactive authentication");
- state(data, SSH_AUTH_DONE);
+ myssh_state(data, sshc, SSH_AUTH_DONE);
}
else {
MOVE_TO_PASSWD_AUTH;
MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
break;
}
- state(data, SSH_AUTH_PASS);
+ myssh_state(data, sshc, SSH_AUTH_PASS);
FALLTHROUGH();
case SSH_AUTH_PASS:
if(rc == SSH_AUTH_SUCCESS) {
sshc->authed = TRUE;
infof(data, "Completed password authentication");
- state(data, SSH_AUTH_DONE);
+ myssh_state(data, sshc, SSH_AUTH_DONE);
}
else {
MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
conn->writesockfd = CURL_SOCKET_BAD;
if(conn->handler->protocol == CURLPROTO_SFTP) {
- state(data, SSH_SFTP_INIT);
+ myssh_state(data, sshc, SSH_SFTP_INIT);
break;
}
infof(data, "SSH CONNECT phase done");
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
case SSH_SFTP_INIT:
MOVE_TO_ERROR_STATE(sftp_error_to_CURLE(SSH_FX_FAILURE));
break;
}
- state(data, SSH_SFTP_REALPATH);
+ myssh_state(data, sshc, SSH_SFTP_REALPATH);
FALLTHROUGH();
case SSH_SFTP_REALPATH:
/*
since the homedir will remain the same between request but the
working path will not. */
DEBUGF(infof(data, "SSH CONNECT phase done"));
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
case SSH_SFTP_QUOTE_INIT:
- result = Curl_getworkingpath(data, sshc->homedir, &protop->path);
+ result = Curl_getworkingpath(data, sshc->homedir, &sshp->path);
if(result) {
sshc->actualcode = result;
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
}
if(data->set.quote) {
infof(data, "Sending quote commands");
sshc->quote_item = data->set.quote;
- state(data, SSH_SFTP_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE);
}
else {
- state(data, SSH_SFTP_GETINFO);
+ myssh_state(data, sshc, SSH_SFTP_GETINFO);
}
break;
if(data->set.postquote) {
infof(data, "Sending quote commands");
sshc->quote_item = data->set.postquote;
- state(data, SSH_SFTP_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE);
}
else {
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
}
break;
case SSH_SFTP_QUOTE:
/* Send any quote commands */
- sftp_quote(data);
+ sftp_quote(data, sshc, sshp);
break;
case SSH_SFTP_NEXT_QUOTE:
sshc->quote_item = sshc->quote_item->next;
if(sshc->quote_item) {
- state(data, SSH_SFTP_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE);
}
else {
if(sshc->nextstate != SSH_NO_STATE) {
- state(data, sshc->nextstate);
+ myssh_state(data, sshc, sshc->nextstate);
sshc->nextstate = SSH_NO_STATE;
}
else {
- state(data, SSH_SFTP_GETINFO);
+ myssh_state(data, sshc, SSH_SFTP_GETINFO);
}
}
break;
case SSH_SFTP_QUOTE_STAT:
- sftp_quote_stat(data);
+ sftp_quote_stat(data, sshc);
break;
case SSH_SFTP_QUOTE_SETSTAT:
Curl_safefree(sshc->quote_path2);
failf(data, "Attempt to set SFTP stats failed: %s",
ssh_get_error(sshc->ssh_session));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
/* sshc->actualcode = sftp_error_to_CURLE(err);
* the error the libssh2 backend is returning */
break;
}
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
break;
case SSH_SFTP_QUOTE_SYMLINK:
Curl_safefree(sshc->quote_path2);
failf(data, "symlink command failed: %s",
ssh_get_error(sshc->ssh_session));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
break;
case SSH_SFTP_QUOTE_MKDIR:
Curl_safefree(sshc->quote_path1);
failf(data, "mkdir command failed: %s",
ssh_get_error(sshc->ssh_session));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
break;
case SSH_SFTP_QUOTE_RENAME:
Curl_safefree(sshc->quote_path2);
failf(data, "rename command failed: %s",
ssh_get_error(sshc->ssh_session));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
break;
case SSH_SFTP_QUOTE_RMDIR:
Curl_safefree(sshc->quote_path1);
failf(data, "rmdir command failed: %s",
ssh_get_error(sshc->ssh_session));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
break;
case SSH_SFTP_QUOTE_UNLINK:
Curl_safefree(sshc->quote_path1);
failf(data, "rm command failed: %s",
ssh_get_error(sshc->ssh_session));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
break;
case SSH_SFTP_QUOTE_STATVFS:
Curl_safefree(sshc->quote_path1);
failf(data, "statvfs command failed: %s",
ssh_get_error(sshc->ssh_session));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
if(!tmp) {
result = CURLE_OUT_OF_MEMORY;
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
break;
}
result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
free(tmp);
if(result) {
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = result;
}
}
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
break;
}
case SSH_SFTP_GETINFO:
if(data->set.get_filetime) {
- state(data, SSH_SFTP_FILETIME);
+ myssh_state(data, sshc, SSH_SFTP_FILETIME);
}
else {
- state(data, SSH_SFTP_TRANS_INIT);
+ myssh_state(data, sshc, SSH_SFTP_TRANS_INIT);
}
break;
{
sftp_attributes attrs;
- attrs = sftp_stat(sshc->sftp_session, protop->path);
+ attrs = sftp_stat(sshc->sftp_session, sshp->path);
if(attrs) {
data->info.filetime = attrs->mtime;
sftp_attributes_free(attrs);
}
- state(data, SSH_SFTP_TRANS_INIT);
+ myssh_state(data, sshc, SSH_SFTP_TRANS_INIT);
break;
}
case SSH_SFTP_TRANS_INIT:
if(data->state.upload)
- state(data, SSH_SFTP_UPLOAD_INIT);
+ myssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT);
else {
- if(protop->path[strlen(protop->path)-1] == '/')
- state(data, SSH_SFTP_READDIR_INIT);
+ if(sshp->path[strlen(sshp->path)-1] == '/')
+ myssh_state(data, sshc, SSH_SFTP_READDIR_INIT);
else
- state(data, SSH_SFTP_DOWNLOAD_INIT);
+ myssh_state(data, sshc, SSH_SFTP_DOWNLOAD_INIT);
}
break;
sftp_attributes attrs;
if(data->state.resume_from < 0) {
- attrs = sftp_stat(sshc->sftp_session, protop->path);
+ attrs = sftp_stat(sshc->sftp_session, sshp->path);
if(attrs) {
curl_off_t size = attrs->size;
if(size < 0) {
if(sshc->sftp_file)
sftp_close(sshc->sftp_file);
sshc->sftp_file =
- sftp_open(sshc->sftp_session, protop->path,
+ sftp_open(sshc->sftp_session, sshp->path,
flags, (mode_t)data->set.new_file_perms);
if(!sshc->sftp_file) {
err = sftp_get_error(sshc->sftp_session);
if(((err == SSH_FX_NO_SUCH_FILE || err == SSH_FX_FAILURE ||
err == SSH_FX_NO_SUCH_PATH)) &&
(data->set.ftp_create_missing_dirs &&
- (strlen(protop->path) > 1))) {
+ (strlen(sshp->path) > 1))) {
/* try to create the path remotely */
rc = 0;
sshc->secondCreateDirs = 1;
- state(data, SSH_SFTP_CREATE_DIRS_INIT);
+ myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS_INIT);
break;
}
else {
#if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0)
sshc->sftp_send_state = 0;
#endif
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
}
case SSH_SFTP_CREATE_DIRS_INIT:
- if(strlen(protop->path) > 1) {
- sshc->slash_pos = protop->path + 1; /* ignore the leading '/' */
- state(data, SSH_SFTP_CREATE_DIRS);
+ if(strlen(sshp->path) > 1) {
+ sshc->slash_pos = sshp->path + 1; /* ignore the leading '/' */
+ myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS);
}
else {
- state(data, SSH_SFTP_UPLOAD_INIT);
+ myssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT);
}
break;
if(sshc->slash_pos) {
*sshc->slash_pos = 0;
- infof(data, "Creating directory '%s'", protop->path);
- state(data, SSH_SFTP_CREATE_DIRS_MKDIR);
+ infof(data, "Creating directory '%s'", sshp->path);
+ myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS_MKDIR);
break;
}
- state(data, SSH_SFTP_UPLOAD_INIT);
+ myssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT);
break;
case SSH_SFTP_CREATE_DIRS_MKDIR:
/* 'mode' - parameter is preliminary - default to 0644 */
- rc = sftp_mkdir(sshc->sftp_session, protop->path,
+ rc = sftp_mkdir(sshc->sftp_session, sshp->path,
(mode_t)data->set.new_directory_perms);
*sshc->slash_pos = '/';
++sshc->slash_pos;
}
rc = 0; /* clear rc and continue */
}
- state(data, SSH_SFTP_CREATE_DIRS);
+ myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS);
break;
case SSH_SFTP_READDIR_INIT:
Curl_pgrsSetDownloadSize(data, -1);
if(data->req.no_body) {
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
}
* listing
*/
sshc->sftp_dir = sftp_opendir(sshc->sftp_session,
- protop->path);
+ sshp->path);
if(!sshc->sftp_dir) {
failf(data, "Could not open directory for reading: %s",
ssh_get_error(sshc->ssh_session));
MOVE_TO_SFTP_CLOSE_STATE();
break;
}
- state(data, SSH_SFTP_READDIR);
+ myssh_state(data, sshc, SSH_SFTP_READDIR);
break;
case SSH_SFTP_READDIR:
tmpLine = aprintf("%s\n", sshc->readdir_filename);
if(!tmpLine) {
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->actualcode = CURLE_OUT_OF_MEMORY;
break;
}
free(tmpLine);
if(result) {
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
}
else {
if(curlx_dyn_add(&sshc->readdir_buf, sshc->readdir_longentry)) {
sshc->actualcode = CURLE_OUT_OF_MEMORY;
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
}
if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
((sshc->readdir_attrs->permissions & SSH_S_IFMT) ==
SSH_S_IFLNK)) {
- sshc->readdir_linkPath = aprintf("%s%s", protop->path,
+ sshc->readdir_linkPath = aprintf("%s%s", sshp->path,
sshc->readdir_filename);
if(!sshc->readdir_linkPath) {
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->actualcode = CURLE_OUT_OF_MEMORY;
break;
}
- state(data, SSH_SFTP_READDIR_LINK);
+ myssh_state(data, sshc, SSH_SFTP_READDIR_LINK);
break;
}
- state(data, SSH_SFTP_READDIR_BOTTOM);
+ myssh_state(data, sshc, SSH_SFTP_READDIR_BOTTOM);
break;
}
}
else if(sftp_dir_eof(sshc->sftp_dir)) {
- state(data, SSH_SFTP_READDIR_DONE);
+ myssh_state(data, sshc, SSH_SFTP_READDIR_DONE);
break;
}
else {
sshc->readdir_filename = NULL;
sshc->readdir_longentry = NULL;
- state(data, SSH_SFTP_READDIR_BOTTOM);
+ myssh_state(data, sshc, SSH_SFTP_READDIR_BOTTOM);
FALLTHROUGH();
case SSH_SFTP_READDIR_BOTTOM:
if(curlx_dyn_addn(&sshc->readdir_buf, "\n", 1))
sshc->readdir_tmp = NULL;
if(result) {
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
}
else
- state(data, SSH_SFTP_READDIR);
+ myssh_state(data, sshc, SSH_SFTP_READDIR);
break;
case SSH_SFTP_READDIR_DONE:
/* no data to transfer */
Curl_xfer_setup_nop(data);
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
case SSH_SFTP_DOWNLOAD_INIT:
if(sshc->sftp_file)
sftp_close(sshc->sftp_file);
- sshc->sftp_file = sftp_open(sshc->sftp_session, protop->path,
+ sshc->sftp_file = sftp_open(sshc->sftp_session, sshp->path,
O_RDONLY, (mode_t)data->set.new_file_perms);
if(!sshc->sftp_file) {
failf(data, "Could not open remote file for reading: %s",
break;
}
sftp_file_set_nonblocking(sshc->sftp_file);
- state(data, SSH_SFTP_DOWNLOAD_STAT);
+ myssh_state(data, sshc, SSH_SFTP_DOWNLOAD_STAT);
break;
case SSH_SFTP_DOWNLOAD_STAT:
/* no data to transfer */
Curl_xfer_setup_nop(data);
infof(data, "File already completely downloaded");
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
}
Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE);
if(result) {
/* this should never occur; the close state should be entered
at the time the error occurs */
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->actualcode = result;
}
else {
sshc->sftp_recv_state = 0;
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
}
break;
sftp_close(sshc->sftp_file);
sshc->sftp_file = NULL;
}
- Curl_safefree(protop->path);
+ Curl_safefree(sshp->path);
DEBUGF(infof(data, "SFTP DONE done"));
SSH_SFTP_CLOSE to pass the correct result back */
if(sshc->nextstate != SSH_NO_STATE &&
sshc->nextstate != SSH_SFTP_CLOSE) {
- state(data, sshc->nextstate);
+ myssh_state(data, sshc, sshc->nextstate);
sshc->nextstate = SSH_SFTP_CLOSE;
}
else {
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
result = sshc->actualcode;
}
break;
SSH_STRING_FREE_CHAR(sshc->homedir);
- state(data, SSH_SESSION_DISCONNECT);
+ myssh_state(data, sshc, SSH_SESSION_DISCONNECT);
break;
case SSH_SCP_TRANS_INIT:
- result = Curl_getworkingpath(data, sshc->homedir, &protop->path);
+ result = Curl_getworkingpath(data, sshc->homedir, &sshp->path);
if(result) {
sshc->actualcode = result;
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
}
}
sshc->scp_session =
- ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, protop->path);
- state(data, SSH_SCP_UPLOAD_INIT);
+ ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, sshp->path);
+ myssh_state(data, sshc, SSH_SCP_UPLOAD_INIT);
}
else {
sshc->scp_session =
- ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, protop->path);
- state(data, SSH_SCP_DOWNLOAD_INIT);
+ ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, sshp->path);
+ myssh_state(data, sshc, SSH_SCP_DOWNLOAD_INIT);
}
if(!sshc->scp_session) {
break;
}
- rc = ssh_scp_push_file64(sshc->scp_session, protop->path,
+ rc = ssh_scp_push_file64(sshc->scp_session, sshp->path,
(uint64_t)data->state.infilesize,
(int)data->set.new_file_perms);
with both accordingly */
data->state.select_bits = CURL_CSELECT_OUT;
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
break;
}
- state(data, SSH_SCP_DOWNLOAD);
+ myssh_state(data, sshc, SSH_SCP_DOWNLOAD);
FALLTHROUGH();
case SSH_SCP_DOWNLOAD:{
with both accordingly */
data->state.select_bits = CURL_CSELECT_IN;
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
}
case SSH_SCP_DONE:
if(data->state.upload)
- state(data, SSH_SCP_SEND_EOF);
+ myssh_state(data, sshc, SSH_SCP_SEND_EOF);
else
- state(data, SSH_SCP_CHANNEL_FREE);
+ myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE);
break;
case SSH_SCP_SEND_EOF:
}
}
- state(data, SSH_SCP_CHANNEL_FREE);
+ myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE);
break;
case SSH_SCP_CHANNEL_FREE:
ssh_set_blocking(sshc->ssh_session, 0);
- state(data, SSH_SESSION_DISCONNECT);
+ myssh_state(data, sshc, SSH_SESSION_DISCONNECT);
FALLTHROUGH();
case SSH_SESSION_DISCONNECT:
SSH_STRING_FREE_CHAR(sshc->homedir);
- state(data, SSH_SESSION_FREE);
+ myssh_state(data, sshc, SSH_SESSION_FREE);
FALLTHROUGH();
case SSH_SESSION_FREE:
- sshc_cleanup(sshc, data);
+ sshc_cleanup(sshc);
/* the code we are about to return */
result = sshc->actualcode;
memset(sshc, 0, sizeof(struct ssh_conn));
connclose(conn, "SSH session free");
sshc->state = SSH_SESSION_FREE; /* current */
sshc->nextstate = SSH_NO_STATE;
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
case SSH_QUIT:
default:
/* internal error */
sshc->nextstate = SSH_NO_STATE;
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
}
return bitmap;
}
-static void myssh_block2waitfor(struct connectdata *conn, bool block)
+static void myssh_block2waitfor(struct connectdata *conn,
+ struct ssh_conn *sshc,
+ bool block)
{
- struct ssh_conn *sshc = &conn->proto.sshc;
-
/* If it did not block, or nothing was returned by ssh_get_poll_flags
* have the original set */
conn->waitfor = sshc->orig_waitfor;
bool *done)
{
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+ struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY);
bool block; /* we store the status and use that to provide a ssh_getsock()
implementation */
- CURLcode result = myssh_statemach_act(data, &block);
+ CURLcode result;
+ if(!sshc || !sshp)
+ return CURLE_FAILED_INIT;
+ result = myssh_statemach_act(data, sshc, sshp, &block);
*done = (sshc->state == SSH_STOP);
- myssh_block2waitfor(conn, block);
+ myssh_block2waitfor(conn, sshc, block);
return result;
}
static CURLcode myssh_block_statemach(struct Curl_easy *data,
+ struct ssh_conn *sshc,
+ struct SSHPROTO *sshp,
bool disconnect)
{
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
CURLcode result = CURLE_OK;
while((sshc->state != SSH_STOP) && !result) {
timediff_t left = 1000;
struct curltime now = curlx_now();
- result = myssh_statemach_act(data, &block);
+ result = myssh_statemach_act(data, sshc, sshp, &block);
if(result)
break;
return result;
}
+static void myssh_easy_dtor(void *key, size_t klen, void *entry)
+{
+ struct SSHPROTO *sshp = entry;
+ (void)key;
+ (void)klen;
+ Curl_safefree(sshp->path);
+ free(sshp);
+}
+
+static void myssh_conn_dtor(void *key, size_t klen, void *entry)
+{
+ struct ssh_conn *sshc = entry;
+ (void)key;
+ (void)klen;
+ sshc_cleanup(sshc);
+ free(sshc);
+}
+
/*
* SSH setup connection
*/
static CURLcode myssh_setup_connection(struct Curl_easy *data,
struct connectdata *conn)
{
- struct SSHPROTO *ssh;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct SSHPROTO *sshp;
+ struct ssh_conn *sshc;
- if(!sshc->initialised) {
- curlx_dyn_init(&sshc->readdir_buf, CURL_PATH_MAX * 2);
- sshc->initialised = TRUE;
- }
+ sshc = calloc(1, sizeof(*sshc));
+ if(!sshc)
+ return CURLE_OUT_OF_MEMORY;
- data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
- if(!ssh)
+ curlx_dyn_init(&sshc->readdir_buf, CURL_PATH_MAX * 2);
+ sshc->initialised = TRUE;
+ if(Curl_conn_meta_set(conn, CURL_META_SSH_CONN, sshc, myssh_conn_dtor))
+ return CURLE_OUT_OF_MEMORY;
+
+ sshp = calloc(1, sizeof(*sshp));
+ if(!sshp ||
+ Curl_meta_set(data, CURL_META_SSH_EASY, sshp, myssh_easy_dtor))
return CURLE_OUT_OF_MEMORY;
return CURLE_OK;
*/
static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
{
- struct ssh_conn *ssh;
CURLcode result;
struct connectdata *conn = data->conn;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+ struct SSHPROTO *ssh = Curl_meta_get(data, CURL_META_SSH_EASY);
curl_socket_t sock = conn->sock[FIRSTSOCKET];
int rc;
- /* initialize per-handle data if not already */
- if(!data->req.p.ssh)
- myssh_setup_connection(data, conn);
+ if(!sshc || !ssh)
+ return CURLE_FAILED_INIT;
/* We default to persistent connections. We set this already in this connect
function to make the reuse checks properly be able to check this bit. */
conn->send[FIRSTSOCKET] = sftp_send;
}
- ssh = &conn->proto.sshc;
-
- ssh->ssh_session = ssh_new();
- if(!ssh->ssh_session) {
+ sshc->ssh_session = ssh_new();
+ if(!sshc->ssh_session) {
failf(data, "Failure initialising ssh session");
return CURLE_FAILED_INIT;
}
if(conn->bits.ipv6_ip) {
char ipv6[MAX_IPADR_LEN];
msnprintf(ipv6, sizeof(ipv6), "[%s]", conn->host.name);
- rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, ipv6);
+ rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_HOST, ipv6);
}
else
- rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name);
+ rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_HOST, conn->host.name);
if(rc != SSH_OK) {
failf(data, "Could not set remote host");
return CURLE_FAILED_INIT;
}
- rc = ssh_options_parse_config(ssh->ssh_session, NULL);
+ rc = ssh_options_parse_config(sshc->ssh_session, NULL);
if(rc != SSH_OK) {
infof(data, "Could not parse SSH configuration files");
/* ignore */
}
- rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock);
+ rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_FD, &sock);
if(rc != SSH_OK) {
failf(data, "Could not set socket");
return CURLE_FAILED_INIT;
if(conn->user && conn->user[0] != '\0') {
infof(data, "User: %s", conn->user);
- rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user);
+ rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_USER, conn->user);
if(rc != SSH_OK) {
failf(data, "Could not set user");
return CURLE_FAILED_INIT;
if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
infof(data, "Known hosts: %s", data->set.str[STRING_SSH_KNOWNHOSTS]);
- rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS,
+ rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_KNOWNHOSTS,
data->set.str[STRING_SSH_KNOWNHOSTS]);
if(rc != SSH_OK) {
failf(data, "Could not set known hosts file path");
}
if(conn->remote_port) {
- rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_PORT,
+ rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_PORT,
&conn->remote_port);
if(rc != SSH_OK) {
failf(data, "Could not set remote port");
}
if(data->set.ssh_compression) {
- rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_COMPRESSION,
+ rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_COMPRESSION,
"zlib,zlib@openssh.com,none");
if(rc != SSH_OK) {
failf(data, "Could not set compression");
}
}
- ssh->privkey = NULL;
- ssh->pubkey = NULL;
+ sshc->privkey = NULL;
+ sshc->pubkey = NULL;
if(data->set.str[STRING_SSH_PUBLIC_KEY]) {
rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY],
- &ssh->pubkey);
+ &sshc->pubkey);
if(rc != SSH_OK) {
failf(data, "Could not load public key file");
return CURLE_FAILED_INIT;
/* we do not verify here, we do it at the state machine,
* after connection */
- state(data, SSH_INIT);
+ myssh_state(data, sshc, SSH_INIT);
result = myssh_multi_statemach(data, done);
bool *connected, bool *dophase_done)
{
CURLcode result = CURLE_OK;
+ struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN);
DEBUGF(infof(data, "DO phase starts"));
*dophase_done = FALSE; /* not done yet */
+ if(!sshc)
+ return CURLE_FAILED_INIT;
/* start the first command in the DO phase */
- state(data, SSH_SCP_TRANS_INIT);
+ myssh_state(data, sshc, SSH_SCP_TRANS_INIT);
result = myssh_multi_statemach(data, dophase_done);
CURLcode result;
bool connected = FALSE;
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
*done = FALSE; /* default to false */
+ if(!sshc)
+ return CURLE_FAILED_INIT;
data->req.size = -1; /* make sure this is unknown at this point */
return result;
}
-static void sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data)
+static void sshc_cleanup(struct ssh_conn *sshc)
{
- (void)data;
if(sshc->initialised) {
if(sshc->ssh_session) {
ssh_free(sshc->ssh_session);
bool dead_connection)
{
CURLcode result = CURLE_OK;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+ struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY);
(void) dead_connection;
- if(sshc->ssh_session) {
+ if(sshc && sshc->ssh_session && sshp) {
/* only if there is a session still around to use! */
- state(data, SSH_SESSION_DISCONNECT);
+ myssh_state(data, sshc, SSH_SESSION_DISCONNECT);
- result = myssh_block_statemach(data, TRUE);
+ result = myssh_block_statemach(data, sshc, sshp, TRUE);
}
- sshc_cleanup(sshc, data);
return result;
}
/* generic done function for both SCP and SFTP called from their specific
done functions */
-static CURLcode myssh_done(struct Curl_easy *data, CURLcode status)
+static CURLcode myssh_done(struct Curl_easy *data,
+ struct ssh_conn *sshc,
+ CURLcode status)
{
CURLcode result = CURLE_OK;
- struct SSHPROTO *protop = data->req.p.ssh;
+ struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY);
if(!status) {
/* run the state-machine */
- result = myssh_block_statemach(data, FALSE);
+ result = myssh_block_statemach(data, sshc, sshp, FALSE);
}
else
result = status;
- if(protop)
- Curl_safefree(protop->path);
if(Curl_pgrsDone(data))
return CURLE_ABORTED_BY_CALLBACK;
static CURLcode scp_done(struct Curl_easy *data, CURLcode status,
bool premature)
{
+ struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN);
(void) premature; /* not used */
+ if(!sshc)
+ return CURLE_FAILED_INIT;
if(!status)
- state(data, SSH_SCP_DONE);
-
- return myssh_done(data, status);
+ myssh_state(data, sshc, SSH_SCP_DONE);
+ return myssh_done(data, sshc, status);
}
static ssize_t scp_send(struct Curl_easy *data, int sockindex,
{
int rc;
struct connectdata *conn = data->conn;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
(void) sockindex; /* we only support SCP on the fixed known primary socket */
- (void) err;
(void)eos;
- rc = ssh_scp_write(conn->proto.sshc.scp_session, mem, len);
+ if(!sshc) {
+ *err = CURLE_FAILED_INIT;
+ return -1;
+ }
+
+ rc = ssh_scp_write(sshc->scp_session, mem, len);
#if 0
/* The following code is misleading, mostly added as wishful thinking
* that libssh at some point will implement non-blocking ssh_scp_write/read.
* Currently rc can only be number of bytes read or SSH_ERROR. */
- myssh_block2waitfor(conn, (rc == SSH_AGAIN));
+ myssh_block2waitfor(conn, sshc, (rc == SSH_AGAIN));
if(rc == SSH_AGAIN) {
*err = CURLE_AGAIN;
{
ssize_t nread;
struct connectdata *conn = data->conn;
- (void) err;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
(void) sockindex; /* we only support SCP on the fixed known primary socket */
+ if(!sshc) {
+ *err = CURLE_FAILED_INIT;
+ return -1;
+ }
/* libssh returns int */
- nread = ssh_scp_read(conn->proto.sshc.scp_session, mem, len);
+ nread = ssh_scp_read(sshc->scp_session, mem, len);
#if 0
/* The following code is misleading, mostly added as wishful thinking
* that libssh at some point will implement non-blocking ssh_scp_write/read.
* Currently rc can only be SSH_OK or SSH_ERROR. */
- myssh_block2waitfor(conn, (nread == SSH_AGAIN));
+ myssh_block2waitfor(conn, sshc, (nread == SSH_AGAIN));
if(nread == SSH_AGAIN) {
*err = CURLE_AGAIN;
nread = -1;
bool *connected,
bool *dophase_done)
{
+ struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN);
CURLcode result = CURLE_OK;
DEBUGF(infof(data, "DO phase starts"));
*dophase_done = FALSE; /* not done yet */
+ if(!sshc)
+ return CURLE_FAILED_INIT;
/* start the first command in the DO phase */
- state(data, SSH_SFTP_QUOTE_INIT);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_INIT);
/* run the state-machine */
result = myssh_multi_statemach(data, dophase_done);
struct connectdata *conn,
bool dead_connection)
{
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+ struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY);
CURLcode result = CURLE_OK;
(void) dead_connection;
DEBUGF(infof(data, "SSH DISCONNECT starts now"));
- if(conn->proto.sshc.ssh_session) {
+ if(sshc && sshc->ssh_session && sshp) {
/* only if there is a session still around to use! */
- state(data, SSH_SFTP_SHUTDOWN);
- result = myssh_block_statemach(data, TRUE);
+ myssh_state(data, sshc, SSH_SFTP_SHUTDOWN);
+ result = myssh_block_statemach(data, sshc, sshp, TRUE);
}
DEBUGF(infof(data, "SSH DISCONNECT is done"));
- sshc_cleanup(sshc, data);
-
return result;
}
bool premature)
{
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+ if(!sshc)
+ return CURLE_FAILED_INIT;
if(!status) {
/* Post quote commands are executed after the SFTP_CLOSE state to avoid
errors that could happen due to open file handles during POSTQUOTE
operation */
if(!premature && data->set.postquote && !conn->bits.retry)
sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
}
- return myssh_done(data, status);
+ return myssh_done(data, sshc, status);
}
/* return number of sent bytes */
{
ssize_t nwrite;
struct connectdata *conn = data->conn;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
(void)sockindex;
(void)eos;
+ if(!sshc) {
+ *err = CURLE_FAILED_INIT;
+ return -1;
+ }
/* limit the writes to the maximum specified in Section 3 of
* https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02
*/
if(len > 32768)
len = 32768;
#if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0)
- switch(conn->proto.sshc.sftp_send_state) {
+ switch(sshc->sftp_send_state) {
case 0:
- sftp_file_set_nonblocking(conn->proto.sshc.sftp_file);
- if(sftp_aio_begin_write(conn->proto.sshc.sftp_file, mem, len,
- &conn->proto.sshc.sftp_aio) == SSH_ERROR) {
+ sftp_file_set_nonblocking(sshc->sftp_file);
+ if(sftp_aio_begin_write(sshc->sftp_file, mem, len,
+ &sshc->sftp_aio) == SSH_ERROR) {
*err = CURLE_SEND_ERROR;
return -1;
}
- conn->proto.sshc.sftp_send_state = 1;
+ sshc->sftp_send_state = 1;
FALLTHROUGH();
case 1:
- nwrite = sftp_aio_wait_write(&conn->proto.sshc.sftp_aio);
- myssh_block2waitfor(conn, (nwrite == SSH_AGAIN) ? TRUE : FALSE);
+ nwrite = sftp_aio_wait_write(&sshc->sftp_aio);
+ myssh_block2waitfor(conn, sshc, (nwrite == SSH_AGAIN) ? TRUE : FALSE);
if(nwrite == SSH_AGAIN) {
*err = CURLE_AGAIN;
return 0;
*err = CURLE_SEND_ERROR;
return -1;
}
- if(conn->proto.sshc.sftp_aio) {
- sftp_aio_free(conn->proto.sshc.sftp_aio);
- conn->proto.sshc.sftp_aio = NULL;
+ if(sshc->sftp_aio) {
+ sftp_aio_free(sshc->sftp_aio);
+ sshc->sftp_aio = NULL;
}
- conn->proto.sshc.sftp_send_state = 0;
+ sshc->sftp_send_state = 0;
return nwrite;
default:
/* we never reach here */
return -1;
}
#else
- nwrite = sftp_write(conn->proto.sshc.sftp_file, mem, len);
+ nwrite = sftp_write(sshc->sftp_file, mem, len);
- myssh_block2waitfor(conn, FALSE);
+ myssh_block2waitfor(conn, sshc, FALSE);
#if 0 /* not returned by libssh on write */
if(nwrite == SSH_AGAIN) {
{
ssize_t nread;
struct connectdata *conn = data->conn;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
(void)sockindex;
DEBUGASSERT(len < CURL_MAX_READ_SIZE);
+ if(!sshc) {
+ *err = CURLE_FAILED_INIT;
+ return -1;
+ }
- switch(conn->proto.sshc.sftp_recv_state) {
+ switch(sshc->sftp_recv_state) {
case 0:
- conn->proto.sshc.sftp_file_index =
- sftp_async_read_begin(conn->proto.sshc.sftp_file,
- (uint32_t)len);
- if(conn->proto.sshc.sftp_file_index < 0) {
+ sshc->sftp_file_index =
+ sftp_async_read_begin(sshc->sftp_file, (uint32_t)len);
+ if(sshc->sftp_file_index < 0) {
*err = CURLE_RECV_ERROR;
return -1;
}
FALLTHROUGH();
case 1:
- conn->proto.sshc.sftp_recv_state = 1;
-
- nread = sftp_async_read(conn->proto.sshc.sftp_file,
- mem, (uint32_t)len,
- (uint32_t)conn->proto.sshc.sftp_file_index);
+ sshc->sftp_recv_state = 1;
+ nread = sftp_async_read(sshc->sftp_file, mem, (uint32_t)len,
+ (uint32_t)sshc->sftp_file_index);
- myssh_block2waitfor(conn, (nread == SSH_AGAIN));
+ myssh_block2waitfor(conn, sshc, (nread == SSH_AGAIN));
if(nread == SSH_AGAIN) {
*err = CURLE_AGAIN;
return -1;
}
- conn->proto.sshc.sftp_recv_state = 0;
+ sshc->sftp_recv_state = 0;
return nread;
default:
}
}
-static void sftp_quote(struct Curl_easy *data)
+static void sftp_quote(struct Curl_easy *data,
+ struct ssh_conn *sshc,
+ struct SSHPROTO *sshp)
{
const char *cp;
- struct connectdata *conn = data->conn;
- struct SSHPROTO *protop = data->req.p.ssh;
- struct ssh_conn *sshc = &conn->proto.sshc;
CURLcode result;
/*
if(strcasecompare("pwd", cmd)) {
/* output debug output if that is requested */
- char *tmp = aprintf("257 \"%s\" is current directory.\n",
- protop->path);
+ char *tmp = aprintf("257 \"%s\" is current directory.\n", sshp->path);
if(!tmp) {
sshc->actualcode = CURLE_OUT_OF_MEMORY;
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
return;
}
result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
free(tmp);
if(result) {
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = result;
}
else
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
return;
}
cp = strchr(cmd, ' ');
if(!cp) {
failf(data, "Syntax error in SFTP command. Supply parameter(s)");
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
return;
failf(data, "Out of memory");
else
failf(data, "Syntax error: Bad first parameter");
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = result;
return;
failf(data, "Syntax error in chgrp/chmod/chown/atime/mtime: "
"Bad second parameter");
Curl_safefree(sshc->quote_path1);
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = result;
return;
}
sshc->quote_attrs = NULL;
- state(data, SSH_SFTP_QUOTE_STAT);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_STAT);
return;
}
if(!strncmp(cmd, "ln ", 3) ||
else
failf(data, "Syntax error in ln/symlink: Bad second parameter");
Curl_safefree(sshc->quote_path1);
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = result;
return;
}
- state(data, SSH_SFTP_QUOTE_SYMLINK);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_SYMLINK);
return;
}
else if(!strncmp(cmd, "mkdir ", 6)) {
/* create dir */
- state(data, SSH_SFTP_QUOTE_MKDIR);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_MKDIR);
return;
}
else if(!strncmp(cmd, "rename ", 7)) {
else
failf(data, "Syntax error in rename: Bad second parameter");
Curl_safefree(sshc->quote_path1);
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = result;
return;
}
- state(data, SSH_SFTP_QUOTE_RENAME);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_RENAME);
return;
}
else if(!strncmp(cmd, "rmdir ", 6)) {
/* delete dir */
- state(data, SSH_SFTP_QUOTE_RMDIR);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_RMDIR);
return;
}
else if(!strncmp(cmd, "rm ", 3)) {
- state(data, SSH_SFTP_QUOTE_UNLINK);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_UNLINK);
return;
}
#ifdef HAS_STATVFS_SUPPORT
else if(!strncmp(cmd, "statvfs ", 8)) {
- state(data, SSH_SFTP_QUOTE_STATVFS);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_STATVFS);
return;
}
#endif
failf(data, "Unknown SFTP command");
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
}
-static void sftp_quote_stat(struct Curl_easy *data)
+static void sftp_quote_stat(struct Curl_easy *data,
+ struct ssh_conn *sshc)
{
- struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
char *cmd = sshc->quote_item->data;
sshc->acceptfail = FALSE;
Curl_safefree(sshc->quote_path2);
failf(data, "Attempt to get SFTP stats failed: %d",
sftp_get_error(sshc->sftp_session));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
return;
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
failf(data, "Syntax error: chgrp gid not a number");
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
return;
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
failf(data, "Syntax error: chmod permissions not a number");
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
return;
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
failf(data, "Syntax error: chown uid not a number");
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
return;
if(fail) {
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
return;
}
/* Now send the completed structure... */
- state(data, SSH_SFTP_QUOTE_SETSTAT);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_SETSTAT);
return;
}
static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc);
static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc);
static LIBSSH2_FREE_FUNC(my_libssh2_free);
-static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data);
+static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data,
+ struct ssh_conn *sshc);
static CURLcode ssh_connect(struct Curl_easy *data, bool *done);
static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done);
static CURLcode ssh_do(struct Curl_easy *data, bool *done);
* SSH State machine related code
*/
/* This is the ONLY way to change SSH state! */
-static void state(struct Curl_easy *data, sshstate nowstate)
+static void myssh_state(struct Curl_easy *data,
+ struct ssh_conn *sshc,
+ sshstate nowstate)
{
- struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
/* for debug purposes */
static const char * const names[] = {
(void *)sshc, names[sshc->state], names[nowstate]);
}
#endif
-
+ (void)data;
sshc->state = nowstate;
}
return keytype;
}
-static CURLcode ssh_knownhost(struct Curl_easy *data)
+static CURLcode ssh_knownhost(struct Curl_easy *data,
+ struct ssh_conn *sshc)
{
int sshkeytype = 0;
size_t keylen = 0;
if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
/* we are asked to verify the host against a file */
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
struct libssh2_knownhost *host = NULL;
const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
&keylen, &sshkeytype);
switch(rc) {
default: /* unknown return codes will equal reject */
case CURLKHSTAT_REJECT:
- state(data, SSH_SESSION_FREE);
+ myssh_state(data, sshc, SSH_SESSION_FREE);
FALLTHROUGH();
case CURLKHSTAT_DEFER:
/* DEFER means bail out but keep the SSH_HOSTKEY state */
return result;
}
-static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
+static CURLcode ssh_check_fingerprint(struct Curl_easy *data,
+ struct ssh_conn *sshc)
{
- struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
const char *pubkey_sha256 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256];
failf(data,
"Denied establishing ssh session: sha256 fingerprint "
"not available");
- state(data, SSH_SESSION_FREE);
+ myssh_state(data, sshc, SSH_SESSION_FREE);
sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
return sshc->actualcode;
}
* See libssh2_hostkey_hash documentation. */
if(curlx_base64_encode(fingerprint, 32, &fingerprint_b64,
&fingerprint_b64_len) != CURLE_OK) {
- state(data, SSH_SESSION_FREE);
+ myssh_state(data, sshc, SSH_SESSION_FREE);
sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
return sshc->actualcode;
}
if(!fingerprint_b64) {
failf(data, "sha256 fingerprint could not be encoded");
- state(data, SSH_SESSION_FREE);
+ myssh_state(data, sshc, SSH_SESSION_FREE);
sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
return sshc->actualcode;
}
"Denied establishing ssh session: mismatch sha256 fingerprint. "
"Remote %s is not equal to %s", fingerprint_b64, pubkey_sha256);
free(fingerprint_b64);
- state(data, SSH_SESSION_FREE);
+ myssh_state(data, sshc, SSH_SESSION_FREE);
sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
return sshc->actualcode;
}
"Denied establishing ssh session: md5 fingerprint "
"not available");
}
- state(data, SSH_SESSION_FREE);
+ myssh_state(data, sshc, SSH_SESSION_FREE);
sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
return sshc->actualcode;
}
(int)keytype, remotekey, keylen);
Curl_set_in_callback(data, FALSE);
if(rc!= CURLKHMATCH_OK) {
- state(data, SSH_SESSION_FREE);
+ myssh_state(data, sshc, SSH_SESSION_FREE);
sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
return sshc->actualcode;
}
}
else {
- state(data, SSH_SESSION_FREE);
+ myssh_state(data, sshc, SSH_SESSION_FREE);
sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
return sshc->actualcode;
}
return CURLE_OK;
}
else {
- return ssh_knownhost(data);
+ return ssh_knownhost(data, sshc);
}
}
else {
* ssh_force_knownhost_key_type() will check the known hosts file and try to
* force a specific public key type from the server if an entry is found.
*/
-static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data)
+static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data,
+ struct ssh_conn *sshc)
{
CURLcode result = CURLE_OK;
const char *hostkey_method = NULL;
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
struct libssh2_knownhost* store = NULL;
const char *kh_name_end = NULL;
size_t kh_name_size = 0;
result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
free(tmp);
if(!result)
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
return result;
}
return result;
}
memset(&sshp->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
- state(data, SSH_SFTP_QUOTE_STAT);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_STAT);
return result;
}
if(!strncmp(cmd, "ln ", 3) ||
Curl_safefree(sshc->quote_path1);
return result;
}
- state(data, SSH_SFTP_QUOTE_SYMLINK);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_SYMLINK);
return result;
}
else if(!strncmp(cmd, "mkdir ", 6)) {
/* create dir */
- state(data, SSH_SFTP_QUOTE_MKDIR);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_MKDIR);
return result;
}
else if(!strncmp(cmd, "rename ", 7)) {
Curl_safefree(sshc->quote_path1);
return result;
}
- state(data, SSH_SFTP_QUOTE_RENAME);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_RENAME);
return result;
}
else if(!strncmp(cmd, "rmdir ", 6)) {
/* delete dir */
- state(data, SSH_SFTP_QUOTE_RMDIR);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_RMDIR);
return result;
}
else if(!strncmp(cmd, "rm ", 3)) {
- state(data, SSH_SFTP_QUOTE_UNLINK);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_UNLINK);
return result;
}
else if(!strncmp(cmd, "statvfs ", 8)) {
- state(data, SSH_SFTP_QUOTE_STATVFS);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_STATVFS);
return result;
}
sftperr = LIBSSH2_FX_OK; /* not an sftp error at all */
if(sshc->secondCreateDirs) {
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->actualcode = sftperr != LIBSSH2_FX_OK ?
sftp_libssh2_error_to_CURLE(sftperr) : CURLE_SSH;
failf(data, "Creating the dir/file failed: %s",
(strlen(sshp->path) > 1))) {
/* try to create the path remotely */
sshc->secondCreateDirs = 1;
- state(data, SSH_SFTP_CREATE_DIRS_INIT);
+ myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS_INIT);
return CURLE_OK;
}
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->actualcode = sftperr != LIBSSH2_FX_OK ?
sftp_libssh2_error_to_CURLE(sftperr) : CURLE_SSH;
if(!sshc->actualcode) {
timeout here */
Curl_expire(data, 0, EXPIRE_RUN_NOW);
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
return CURLE_OK;
}
if(out_of_memory || !sshc->rsa) {
Curl_safefree(sshc->rsa);
Curl_safefree(sshc->rsa_pub);
- state(data, SSH_SESSION_FREE);
+ myssh_state(data, sshc, SSH_SESSION_FREE);
sshc->actualcode = CURLE_OUT_OF_MEMORY;
return CURLE_OUT_OF_MEMORY;
}
infof(data, "Using SSH public key file '%s'", sshc->rsa_pub);
infof(data, "Using SSH private key file '%s'", sshc->rsa);
- state(data, SSH_AUTH_PKEY);
+ myssh_state(data, sshc, SSH_AUTH_PKEY);
}
else {
- state(data, SSH_AUTH_PASS_INIT);
+ myssh_state(data, sshc, SSH_AUTH_PASS_INIT);
}
return CURLE_OK;
}
}
/* Now send the completed structure... */
- state(data, SSH_SFTP_QUOTE_SETSTAT);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_SETSTAT);
return CURLE_OK;
fail:
Curl_safefree(sshc->quote_path1);
/* no data to transfer */
Curl_xfer_setup_nop(data);
infof(data, "File already completely downloaded");
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
return CURLE_OK;
}
Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE);
out writableable as the underlying libssh2 recv function will deal
with both accordingly */
data->state.select_bits = CURL_CSELECT_IN;
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
return CURLE_OK;
}
LIBSSH2_SFTP_S_IFLNK)) {
result = curlx_dyn_addf(&sshp->readdir_link, "%s%s", sshp->path,
sshp->readdir_filename);
- state(data, SSH_SFTP_READDIR_LINK);
+ myssh_state(data, sshc, SSH_SFTP_READDIR_LINK);
}
else {
- state(data, SSH_SFTP_READDIR_BOTTOM);
+ myssh_state(data, sshc, SSH_SFTP_READDIR_BOTTOM);
}
}
return result;
}
}
else if(!rc) {
- state(data, SSH_SFTP_READDIR_DONE);
+ myssh_state(data, sshc, SSH_SFTP_READDIR_DONE);
}
else {
unsigned long sftperr = libssh2_sftp_last_error(sshc->sftp_session);
failf(data, "Could not open remote file for reading: %s :: %d",
sftp_libssh2_strerror(sftperr),
libssh2_session_last_errno(sshc->ssh_session));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
}
return result;
}
* meaning it wants to be called again when the socket is ready
*/
-static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block)
+static CURLcode ssh_statemachine(struct Curl_easy *data,
+ struct ssh_conn *sshc,
+ struct SSHPROTO *sshp,
+ bool *block)
{
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
- struct SSHPROTO *sshp = data->req.p.ssh;
- struct ssh_conn *sshc = &conn->proto.sshc;
int rc = LIBSSH2_ERROR_NONE;
*block = 0; /* we are not blocking by default */
non-blocking */
libssh2_session_set_blocking(sshc->ssh_session, 0);
- result = ssh_force_knownhost_key_type(data);
+ result = ssh_force_knownhost_key_type(data, sshc);
if(result) {
- state(data, SSH_SESSION_FREE);
+ myssh_state(data, sshc, SSH_SESSION_FREE);
sshc->actualcode = result;
break;
}
- state(data, SSH_S_STARTUP);
+ myssh_state(data, sshc, SSH_S_STARTUP);
FALLTHROUGH();
case SSH_S_STARTUP:
(void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0);
failf(data, "Failure establishing ssh session: %d, %s", rc, err_msg);
- state(data, SSH_SESSION_FREE);
+ myssh_state(data, sshc, SSH_SESSION_FREE);
sshc->actualcode = CURLE_FAILED_INIT;
break;
}
- state(data, SSH_HOSTKEY);
+ myssh_state(data, sshc, SSH_HOSTKEY);
FALLTHROUGH();
case SSH_HOSTKEY:
* against our known hosts. How that is handled (reading from file,
* whatever) is up to us.
*/
- result = ssh_check_fingerprint(data);
+ result = ssh_check_fingerprint(data, sshc);
if(!result)
- state(data, SSH_AUTHLIST);
+ myssh_state(data, sshc, SSH_AUTHLIST);
/* ssh_check_fingerprint sets state appropriately on error */
break;
if(libssh2_userauth_authenticated(sshc->ssh_session)) {
sshc->authed = TRUE;
infof(data, "SSH user accepted with no authentication");
- state(data, SSH_AUTH_DONE);
+ myssh_state(data, sshc, SSH_AUTH_DONE);
break;
}
rc = libssh2_session_last_errno(sshc->ssh_session);
if(rc == LIBSSH2_ERROR_EAGAIN)
rc = LIBSSH2_ERROR_EAGAIN;
else {
- state(data, SSH_SESSION_FREE);
+ myssh_state(data, sshc, SSH_SESSION_FREE);
sshc->actualcode = libssh2_session_error_to_CURLE(rc);
}
break;
infof(data, "SSH authentication methods available: %s",
sshc->authlist);
- state(data, SSH_AUTH_PKEY_INIT);
+ myssh_state(data, sshc, SSH_AUTH_PKEY_INIT);
break;
case SSH_AUTH_PKEY_INIT:
if(rc == 0) {
sshc->authed = TRUE;
infof(data, "Initialized SSH public key authentication");
- state(data, SSH_AUTH_DONE);
+ myssh_state(data, sshc, SSH_AUTH_DONE);
}
else {
char *err_msg = NULL;
&err_msg, NULL, 0);
}
infof(data, "SSH public key authentication failed: %s", err_msg);
- state(data, SSH_AUTH_PASS_INIT);
+ myssh_state(data, sshc, SSH_AUTH_PASS_INIT);
rc = 0; /* clear rc and continue */
}
break;
case SSH_AUTH_PASS_INIT:
if((data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD) &&
(strstr(sshc->authlist, "password") != NULL)) {
- state(data, SSH_AUTH_PASS);
+ myssh_state(data, sshc, SSH_AUTH_PASS);
}
else {
- state(data, SSH_AUTH_HOST_INIT);
+ myssh_state(data, sshc, SSH_AUTH_HOST_INIT);
rc = 0; /* clear rc and continue */
}
break;
if(rc == 0) {
sshc->authed = TRUE;
infof(data, "Initialized password authentication");
- state(data, SSH_AUTH_DONE);
+ myssh_state(data, sshc, SSH_AUTH_DONE);
}
else {
- state(data, SSH_AUTH_HOST_INIT);
+ myssh_state(data, sshc, SSH_AUTH_HOST_INIT);
rc = 0; /* clear rc and continue */
}
break;
case SSH_AUTH_HOST_INIT:
if((data->set.ssh_auth_types & CURLSSH_AUTH_HOST) &&
(strstr(sshc->authlist, "hostbased") != NULL)) {
- state(data, SSH_AUTH_HOST);
+ myssh_state(data, sshc, SSH_AUTH_HOST);
}
else {
- state(data, SSH_AUTH_AGENT_INIT);
+ myssh_state(data, sshc, SSH_AUTH_AGENT_INIT);
}
break;
case SSH_AUTH_HOST:
- state(data, SSH_AUTH_AGENT_INIT);
+ myssh_state(data, sshc, SSH_AUTH_AGENT_INIT);
break;
case SSH_AUTH_AGENT_INIT:
if(!sshc->ssh_agent) {
infof(data, "Could not create agent object");
- state(data, SSH_AUTH_KEY_INIT);
+ myssh_state(data, sshc, SSH_AUTH_KEY_INIT);
break;
}
}
break;
if(rc < 0) {
infof(data, "Failure connecting to agent");
- state(data, SSH_AUTH_KEY_INIT);
+ myssh_state(data, sshc, SSH_AUTH_KEY_INIT);
rc = 0; /* clear rc and continue */
}
else {
- state(data, SSH_AUTH_AGENT_LIST);
+ myssh_state(data, sshc, SSH_AUTH_AGENT_LIST);
}
}
else
- state(data, SSH_AUTH_KEY_INIT);
+ myssh_state(data, sshc, SSH_AUTH_KEY_INIT);
break;
case SSH_AUTH_AGENT_LIST:
break;
if(rc < 0) {
infof(data, "Failure requesting identities to agent");
- state(data, SSH_AUTH_KEY_INIT);
+ myssh_state(data, sshc, SSH_AUTH_KEY_INIT);
rc = 0; /* clear rc and continue */
}
else {
- state(data, SSH_AUTH_AGENT);
+ myssh_state(data, sshc, SSH_AUTH_AGENT);
sshc->sshagent_prev_identity = NULL;
}
break;
if(rc == LIBSSH2_ERROR_NONE) {
sshc->authed = TRUE;
infof(data, "Agent based authentication successful");
- state(data, SSH_AUTH_DONE);
+ myssh_state(data, sshc, SSH_AUTH_DONE);
}
else {
- state(data, SSH_AUTH_KEY_INIT);
+ myssh_state(data, sshc, SSH_AUTH_KEY_INIT);
rc = 0; /* clear rc and continue */
}
break;
case SSH_AUTH_KEY_INIT:
if((data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD)
&& (strstr(sshc->authlist, "keyboard-interactive") != NULL)) {
- state(data, SSH_AUTH_KEY);
+ myssh_state(data, sshc, SSH_AUTH_KEY);
}
else {
- state(data, SSH_AUTH_DONE);
+ myssh_state(data, sshc, SSH_AUTH_DONE);
}
break;
sshc->authed = TRUE;
infof(data, "Initialized keyboard interactive authentication");
}
- state(data, SSH_AUTH_DONE);
+ myssh_state(data, sshc, SSH_AUTH_DONE);
break;
case SSH_AUTH_DONE:
if(!sshc->authed) {
failf(data, "Authentication failure");
- state(data, SSH_SESSION_FREE);
+ myssh_state(data, sshc, SSH_SESSION_FREE);
sshc->actualcode = CURLE_LOGIN_DENIED;
break;
}
conn->writesockfd = CURL_SOCKET_BAD;
if(conn->handler->protocol == CURLPROTO_SFTP) {
- state(data, SSH_SFTP_INIT);
+ myssh_state(data, sshc, SSH_SFTP_INIT);
break;
}
infof(data, "SSH CONNECT phase done");
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
case SSH_SFTP_INIT:
(void)libssh2_session_last_error(sshc->ssh_session,
&err_msg, NULL, 0);
failf(data, "Failure initializing sftp session: %s", err_msg);
- state(data, SSH_SESSION_FREE);
+ myssh_state(data, sshc, SSH_SESSION_FREE);
sshc->actualcode = CURLE_FAILED_INIT;
break;
}
- state(data, SSH_SFTP_REALPATH);
+ myssh_state(data, sshc, SSH_SFTP_REALPATH);
break;
case SSH_SFTP_REALPATH:
free(sshc->homedir);
sshc->homedir = strdup(sshp->readdir_filename);
if(!sshc->homedir) {
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->actualcode = CURLE_OUT_OF_MEMORY;
break;
}
sshc->actualcode = result;
DEBUGF(infof(data, "error = %lu makes libcurl = %d",
sftperr, (int)result));
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
}
since the homedir will remain the same between request but the
working path will not. */
DEBUGF(infof(data, "SSH CONNECT phase done"));
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
case SSH_SFTP_QUOTE_INIT:
result = Curl_getworkingpath(data, sshc->homedir, &sshp->path);
if(result) {
sshc->actualcode = result;
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
}
if(data->set.quote) {
infof(data, "Sending quote commands");
sshc->quote_item = data->set.quote;
- state(data, SSH_SFTP_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE);
}
else {
- state(data, SSH_SFTP_GETINFO);
+ myssh_state(data, sshc, SSH_SFTP_GETINFO);
}
break;
if(data->set.postquote) {
infof(data, "Sending quote commands");
sshc->quote_item = data->set.postquote;
- state(data, SSH_SFTP_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE);
}
else {
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
}
break;
/* Send quote commands */
result = sftp_quote(data, sshc, sshp);
if(result) {
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = result;
}
sshc->quote_item = sshc->quote_item->next;
if(sshc->quote_item) {
- state(data, SSH_SFTP_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE);
}
else {
if(sshc->nextstate != SSH_NO_STATE) {
- state(data, sshc->nextstate);
+ myssh_state(data, sshc, sshc->nextstate);
sshc->nextstate = SSH_NO_STATE;
}
else {
- state(data, SSH_SFTP_GETINFO);
+ myssh_state(data, sshc, SSH_SFTP_GETINFO);
}
}
break;
case SSH_SFTP_QUOTE_STAT:
result = sftp_quote_stat(data, sshc, sshp, block);
if(result) {
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = result;
}
Curl_safefree(sshc->quote_path2);
failf(data, "Attempt to set SFTP stats failed: %s",
sftp_libssh2_strerror(sftperr));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
break;
case SSH_SFTP_QUOTE_SYMLINK:
Curl_safefree(sshc->quote_path2);
failf(data, "symlink command failed: %s",
sftp_libssh2_strerror(sftperr));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
break;
case SSH_SFTP_QUOTE_MKDIR:
Curl_safefree(sshc->quote_path1);
failf(data, "mkdir command failed: %s",
sftp_libssh2_strerror(sftperr));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
break;
case SSH_SFTP_QUOTE_RENAME:
Curl_safefree(sshc->quote_path2);
failf(data, "rename command failed: %s",
sftp_libssh2_strerror(sftperr));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
break;
case SSH_SFTP_QUOTE_RMDIR:
Curl_safefree(sshc->quote_path1);
failf(data, "rmdir command failed: %s",
sftp_libssh2_strerror(sftperr));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
break;
case SSH_SFTP_QUOTE_UNLINK:
unsigned long sftperr = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
failf(data, "rm command failed: %s", sftp_libssh2_strerror(sftperr));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
}
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
break;
case SSH_SFTP_QUOTE_STATVFS:
Curl_safefree(sshc->quote_path1);
failf(data, "statvfs command failed: %s",
sftp_libssh2_strerror(sftperr));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
break;
statvfs.f_namemax);
if(!tmp) {
result = CURLE_OUT_OF_MEMORY;
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
break;
}
result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
free(tmp);
if(result) {
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = result;
}
}
- state(data, SSH_SFTP_NEXT_QUOTE);
+ myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
break;
}
case SSH_SFTP_GETINFO:
if(data->set.get_filetime) {
- state(data, SSH_SFTP_FILETIME);
+ myssh_state(data, sshc, SSH_SFTP_FILETIME);
}
else {
- state(data, SSH_SFTP_TRANS_INIT);
+ myssh_state(data, sshc, SSH_SFTP_TRANS_INIT);
}
break;
data->info.filetime = (time_t)attrs.mtime;
}
- state(data, SSH_SFTP_TRANS_INIT);
+ myssh_state(data, sshc, SSH_SFTP_TRANS_INIT);
break;
}
case SSH_SFTP_TRANS_INIT:
if(data->state.upload)
- state(data, SSH_SFTP_UPLOAD_INIT);
+ myssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT);
else {
if(sshp->path[strlen(sshp->path)-1] == '/')
- state(data, SSH_SFTP_READDIR_INIT);
+ myssh_state(data, sshc, SSH_SFTP_READDIR_INIT);
else
- state(data, SSH_SFTP_DOWNLOAD_INIT);
+ myssh_state(data, sshc, SSH_SFTP_DOWNLOAD_INIT);
}
break;
case SSH_SFTP_UPLOAD_INIT:
result = sftp_upload_init(data, sshc, sshp, block);
if(result) {
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = result;
}
case SSH_SFTP_CREATE_DIRS_INIT:
if(strlen(sshp->path) > 1) {
sshc->slash_pos = sshp->path + 1; /* ignore the leading '/' */
- state(data, SSH_SFTP_CREATE_DIRS);
+ myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS);
}
else {
- state(data, SSH_SFTP_UPLOAD_INIT);
+ myssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT);
}
break;
*sshc->slash_pos = 0;
infof(data, "Creating directory '%s'", sshp->path);
- state(data, SSH_SFTP_CREATE_DIRS_MKDIR);
+ myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS_MKDIR);
break;
}
- state(data, SSH_SFTP_UPLOAD_INIT);
+ myssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT);
break;
case SSH_SFTP_CREATE_DIRS_MKDIR:
(sftperr != LIBSSH2_FX_FAILURE) &&
(sftperr != LIBSSH2_FX_PERMISSION_DENIED)) {
result = sftp_libssh2_error_to_CURLE(sftperr);
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->actualcode = result ? result : CURLE_SSH;
break;
}
rc = 0; /* clear rc and continue */
}
- state(data, SSH_SFTP_CREATE_DIRS);
+ myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS);
break;
case SSH_SFTP_READDIR_INIT:
Curl_pgrsSetDownloadSize(data, -1);
if(data->req.no_body) {
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
}
sftperr = libssh2_sftp_last_error(sshc->sftp_session);
failf(data, "Could not open directory for reading: %s",
sftp_libssh2_strerror(sftperr));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
result = sftp_libssh2_error_to_CURLE(sftperr);
sshc->actualcode = result ? result : CURLE_SSH;
break;
}
- state(data, SSH_SFTP_READDIR);
+ myssh_state(data, sshc, SSH_SFTP_READDIR);
break;
case SSH_SFTP_READDIR:
result = sftp_readdir(data, sshc, sshp, block);
if(result) {
sshc->actualcode = result;
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
}
break;
sshp->readdir_filename);
if(result) {
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->actualcode = result;
break;
}
- state(data, SSH_SFTP_READDIR_BOTTOM);
+ myssh_state(data, sshc, SSH_SFTP_READDIR_BOTTOM);
break;
case SSH_SFTP_READDIR_BOTTOM:
if(result) {
curlx_dyn_free(&sshp->readdir);
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
}
else {
curlx_dyn_reset(&sshp->readdir);
- state(data, SSH_SFTP_READDIR);
+ myssh_state(data, sshc, SSH_SFTP_READDIR);
}
break;
/* no data to transfer */
Curl_xfer_setup_nop(data);
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
case SSH_SFTP_DOWNLOAD_INIT:
sftperr = libssh2_sftp_last_error(sshc->sftp_session);
failf(data, "Could not open remote file for reading: %s",
sftp_libssh2_strerror(sftperr));
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
result = sftp_libssh2_error_to_CURLE(sftperr);
sshc->actualcode = result ? result : CURLE_SSH;
break;
}
- state(data, SSH_SFTP_DOWNLOAD_STAT);
+ myssh_state(data, sshc, SSH_SFTP_DOWNLOAD_STAT);
break;
case SSH_SFTP_DOWNLOAD_STAT:
result = sftp_download_stat(data, sshc, sshp, block);
if(result) {
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = result;
}
SSH_SFTP_CLOSE to pass the correct result back */
if(sshc->nextstate != SSH_NO_STATE &&
sshc->nextstate != SSH_SFTP_CLOSE) {
- state(data, sshc->nextstate);
+ myssh_state(data, sshc, sshc->nextstate);
sshc->nextstate = SSH_SFTP_CLOSE;
}
else {
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
result = sshc->actualcode;
}
break;
Curl_safefree(sshc->homedir);
- state(data, SSH_SESSION_DISCONNECT);
+ myssh_state(data, sshc, SSH_SESSION_DISCONNECT);
break;
case SSH_SCP_TRANS_INIT:
result = Curl_getworkingpath(data, sshc->homedir, &sshp->path);
if(result) {
sshc->actualcode = result;
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
}
if(data->state.infilesize < 0) {
failf(data, "SCP requires a known file size for upload");
sshc->actualcode = CURLE_UPLOAD_FAILED;
- state(data, SSH_SCP_CHANNEL_FREE);
+ myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE);
break;
}
- state(data, SSH_SCP_UPLOAD_INIT);
+ myssh_state(data, sshc, SSH_SCP_UPLOAD_INIT);
}
else {
- state(data, SSH_SCP_DOWNLOAD_INIT);
+ myssh_state(data, sshc, SSH_SCP_DOWNLOAD_INIT);
}
break;
ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session,
&err_msg, NULL, 0));
failf(data, "%s", err_msg);
- state(data, SSH_SCP_CHANNEL_FREE);
+ myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE);
sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
/* Map generic errors to upload failed */
if(sshc->actualcode == CURLE_SSH ||
conn->sockfd = conn->writesockfd;
if(result) {
- state(data, SSH_SCP_CHANNEL_FREE);
+ myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE);
sshc->actualcode = result;
}
else {
with both accordingly */
data->state.select_bits = CURL_CSELECT_OUT;
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
}
break;
ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session,
&err_msg, NULL, 0));
failf(data, "%s", err_msg);
- state(data, SSH_SCP_CHANNEL_FREE);
+ myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE);
sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
break;
}
data->state.select_bits = CURL_CSELECT_IN;
if(result) {
- state(data, SSH_SCP_CHANNEL_FREE);
+ myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE);
sshc->actualcode = result;
}
else
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
}
break;
case SSH_SCP_DONE:
if(data->state.upload)
- state(data, SSH_SCP_SEND_EOF);
+ myssh_state(data, sshc, SSH_SCP_SEND_EOF);
else
- state(data, SSH_SCP_CHANNEL_FREE);
+ myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE);
break;
case SSH_SCP_SEND_EOF:
rc, err_msg);
}
}
- state(data, SSH_SCP_WAIT_EOF);
+ myssh_state(data, sshc, SSH_SCP_WAIT_EOF);
break;
case SSH_SCP_WAIT_EOF:
infof(data, "Failed to get channel EOF: %d %s", rc, err_msg);
}
}
- state(data, SSH_SCP_WAIT_CLOSE);
+ myssh_state(data, sshc, SSH_SCP_WAIT_CLOSE);
break;
case SSH_SCP_WAIT_CLOSE:
infof(data, "Channel failed to close: %d %s", rc, err_msg);
}
}
- state(data, SSH_SCP_CHANNEL_FREE);
+ myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE);
break;
case SSH_SCP_CHANNEL_FREE:
}
DEBUGF(infof(data, "SCP DONE phase complete"));
#if 0 /* PREV */
- state(data, SSH_SESSION_DISCONNECT);
+ myssh_state(data, sshc, SSH_SESSION_DISCONNECT);
#endif
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
result = sshc->actualcode;
break;
Curl_safefree(sshc->homedir);
- state(data, SSH_SESSION_FREE);
+ myssh_state(data, sshc, SSH_SESSION_FREE);
break;
case SSH_SESSION_FREE:
connclose(conn, "SSH session free");
sshc->state = SSH_SESSION_FREE; /* current */
sshc->nextstate = SSH_NO_STATE;
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
case SSH_QUIT:
default:
/* internal error */
sshc->nextstate = SSH_NO_STATE;
- state(data, SSH_STOP);
+ myssh_state(data, sshc, SSH_STOP);
break;
}
* function in all cases so that when it _does not_ return EAGAIN we can
* restore the default wait bits.
*/
-static void ssh_block2waitfor(struct Curl_easy *data, bool block)
+static void ssh_block2waitfor(struct Curl_easy *data,
+ struct ssh_conn *sshc,
+ bool block)
{
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
int dir = 0;
if(block) {
dir = libssh2_session_block_directions(sshc->ssh_session);
static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done)
{
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+ struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY);
CURLcode result = CURLE_OK;
bool block; /* we store the status and use that to provide a ssh_getsock()
implementation */
+ if(!sshc || !sshp)
+ return CURLE_FAILED_INIT;
+
do {
- result = ssh_statemachine(data, &block);
+ result = ssh_statemachine(data, sshc, sshp, &block);
*done = (sshc->state == SSH_STOP);
/* if there is no error, it is not done and it did not EWOULDBLOCK, then
try again */
} while(!result && !*done && !block);
- ssh_block2waitfor(data, block);
+ ssh_block2waitfor(data, sshc, block);
return result;
}
static CURLcode ssh_block_statemach(struct Curl_easy *data,
- struct connectdata *conn,
+ struct ssh_conn *sshc,
+ struct SSHPROTO *sshp,
bool disconnect)
{
- struct ssh_conn *sshc = &conn->proto.sshc;
CURLcode result = CURLE_OK;
struct curltime dis = curlx_now();
timediff_t left = 1000;
struct curltime now = curlx_now();
- result = ssh_statemachine(data, &block);
+ result = ssh_statemachine(data, sshc, sshp, &block);
if(result)
break;
if(block) {
int dir = libssh2_session_block_directions(sshc->ssh_session);
- curl_socket_t sock = conn->sock[FIRSTSOCKET];
+ curl_socket_t sock = data->conn->sock[FIRSTSOCKET];
curl_socket_t fd_read = CURL_SOCKET_BAD;
curl_socket_t fd_write = CURL_SOCKET_BAD;
if(LIBSSH2_SESSION_BLOCK_INBOUND & dir)
return result;
}
+static void myssh_easy_dtor(void *key, size_t klen, void *entry)
+{
+ struct SSHPROTO *sshp = entry;
+ (void)key;
+ (void)klen;
+ Curl_safefree(sshp->path);
+ curlx_dyn_free(&sshp->readdir);
+ curlx_dyn_free(&sshp->readdir_link);
+ free(sshp);
+}
+
+static void myssh_conn_dtor(void *key, size_t klen, void *entry)
+{
+ struct ssh_conn *sshc = entry;
+ (void)key;
+ (void)klen;
+ sshc_cleanup(sshc, NULL, TRUE);
+ free(sshc);
+}
+
/*
* SSH setup and connection
*/
static CURLcode ssh_setup_connection(struct Curl_easy *data,
struct connectdata *conn)
{
- struct ssh_conn *sshc = &conn->proto.sshc;
- struct SSHPROTO *ssh;
+ struct ssh_conn *sshc;
+ struct SSHPROTO *sshp;
(void)conn;
- if(!sshc->initialised) {
- /* other ssh implementations do something here, let's keep
- * the initialised flag correct even if this implementation does not. */
- sshc->initialised = TRUE;
- }
+ sshc = calloc(1, sizeof(*sshc));
+ if(!sshc)
+ return CURLE_OUT_OF_MEMORY;
+
+ sshc->initialised = TRUE;
+ if(Curl_conn_meta_set(conn, CURL_META_SSH_CONN, sshc, myssh_conn_dtor))
+ return CURLE_OUT_OF_MEMORY;
- data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
- if(!ssh)
+ sshp = calloc(1, sizeof(*sshp));
+ if(!sshp)
return CURLE_OUT_OF_MEMORY;
- curlx_dyn_init(&ssh->readdir, CURL_PATH_MAX * 2);
- curlx_dyn_init(&ssh->readdir_link, CURL_PATH_MAX);
+ curlx_dyn_init(&sshp->readdir, CURL_PATH_MAX * 2);
+ curlx_dyn_init(&sshp->readdir_link, CURL_PATH_MAX);
+ if(Curl_meta_set(data, CURL_META_SSH_EASY, sshp, myssh_easy_dtor))
+ return CURLE_OUT_OF_MEMORY;
return CURLE_OK;
}
CURLcode result;
struct connectdata *conn = data->conn;
Curl_recv *backup = conn->recv[0];
- struct ssh_conn *ssh = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
int socknum = Curl_conn_sockindex(data, sock);
(void)flags;
+ if(!sshc)
+ return -1;
+
/* swap in the TLS reader function for this call only, and then swap back
the SSH one again */
- conn->recv[0] = ssh->tls_recv;
+ conn->recv[0] = sshc->tls_recv;
result = Curl_conn_recv(data, socknum, buffer, length, &nread);
conn->recv[0] = backup;
if(result == CURLE_AGAIN)
CURLcode result;
struct connectdata *conn = data->conn;
Curl_send *backup = conn->send[0];
- struct ssh_conn *ssh = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
int socknum = Curl_conn_sockindex(data, sock);
(void)flags;
+ if(!sshc)
+ return -1;
+
/* swap in the TLS writer function for this call only, and then swap back
the SSH one again */
- conn->send[0] = ssh->tls_send;
+ conn->send[0] = sshc->tls_send;
result = Curl_conn_send(data, socknum, buffer, length, FALSE, &nwrite);
conn->send[0] = backup;
if(result == CURLE_AGAIN)
#ifdef CURL_LIBSSH2_DEBUG
curl_socket_t sock;
#endif
- struct ssh_conn *sshc;
- CURLcode result;
struct connectdata *conn = data->conn;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+ CURLcode result;
#if LIBSSH2_VERSION_NUM >= 0x010b00
{
}
#endif
- /* initialize per-handle data if not already */
- if(!data->req.p.ssh) {
- result = ssh_setup_connection(data, conn);
- if(result)
- return result;
- }
+ if(!sshc)
+ return CURLE_FAILED_INIT;
/* We default to persistent connections. We set this already in this connect
function to make the reuse checks properly be able to check this bit. */
connkeep(conn, "SSH default");
- sshc = &conn->proto.sshc;
-
if(conn->user)
infof(data, "User: '%s'", conn->user);
else
infof(data, "SSH socket: %d", (int)sock);
#endif /* CURL_LIBSSH2_DEBUG */
- state(data, SSH_INIT);
+ myssh_state(data, sshc, SSH_INIT);
result = ssh_multi_statemach(data, done);
bool *connected,
bool *dophase_done)
{
+ struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN);
CURLcode result = CURLE_OK;
DEBUGF(infof(data, "DO phase starts"));
*dophase_done = FALSE; /* not done yet */
+ if(!sshc)
+ return CURLE_FAILED_INIT;
/* start the first command in the DO phase */
- state(data, SSH_SCP_TRANS_INIT);
+ myssh_state(data, sshc, SSH_SCP_TRANS_INIT);
/* run the state-machine */
result = ssh_multi_statemach(data, dophase_done);
CURLcode result;
bool connected = FALSE;
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
*done = FALSE; /* default to false */
+ if(!sshc)
+ return CURLE_FAILED_INIT;
data->req.size = -1; /* make sure this is unknown at this point */
if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) {
return rc;
}
- if(rc < 0) {
+ if((rc < 0) && data) {
char *err_msg = NULL;
(void)libssh2_session_last_error(sshc->ssh_session,
&err_msg, NULL, 0);
sshc->sshagent_prev_identity = NULL;
}
+ if(sshc->sftp_handle) {
+ rc = libssh2_sftp_close(sshc->sftp_handle);
+ if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) {
+ return rc;
+ }
+ if((rc < 0) && data) {
+ char *err_msg = NULL;
+ (void)libssh2_session_last_error(sshc->ssh_session, &err_msg,
+ NULL, 0);
+ infof(data, "Failed to close libssh2 file: %d %s", rc, err_msg);
+ }
+ sshc->sftp_handle = NULL;
+ }
+
+ if(sshc->ssh_channel) {
+ rc = libssh2_channel_free(sshc->ssh_channel);
+ if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) {
+ return rc;
+ }
+ if((rc < 0) && data) {
+ char *err_msg = NULL;
+ (void)libssh2_session_last_error(sshc->ssh_session,
+ &err_msg, NULL, 0);
+ infof(data, "Failed to free libssh2 scp subsystem: %d %s",
+ rc, err_msg);
+ }
+ sshc->ssh_channel = NULL;
+ }
+
+ if(sshc->sftp_session) {
+ rc = libssh2_sftp_shutdown(sshc->sftp_session);
+ if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) {
+ return rc;
+ }
+ if((rc < 0) && data)
+ infof(data, "Failed to stop libssh2 sftp subsystem");
+ sshc->sftp_session = NULL;
+ }
+
if(sshc->ssh_session) {
rc = libssh2_session_free(sshc->ssh_session);
if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) {
return rc;
}
- if(rc < 0) {
+ if((rc < 0) && data) {
char *err_msg = NULL;
(void)libssh2_session_last_error(sshc->ssh_session,
&err_msg, NULL, 0);
bool dead_connection)
{
CURLcode result = CURLE_OK;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+ struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY);
(void) dead_connection;
- if(sshc->ssh_session) {
+ if(sshc && sshc->ssh_session && sshp) {
/* only if there is a session still around to use! */
- state(data, SSH_SESSION_DISCONNECT);
- result = ssh_block_statemach(data, conn, TRUE);
+ myssh_state(data, sshc, SSH_SESSION_DISCONNECT);
+ result = ssh_block_statemach(data, sshc, sshp, TRUE);
}
- sshc_cleanup(sshc, data, TRUE);
+ if(sshc)
+ sshc_cleanup(sshc, data, TRUE);
return result;
}
done functions */
static CURLcode ssh_done(struct Curl_easy *data, CURLcode status)
{
+ struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN);
+ struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY);
CURLcode result = CURLE_OK;
- struct SSHPROTO *sshp = data->req.p.ssh;
- struct connectdata *conn = data->conn;
+
+ if(!sshc || !sshp)
+ return CURLE_FAILED_INIT;
if(!status)
/* run the state-machine */
- result = ssh_block_statemach(data, conn, FALSE);
+ result = ssh_block_statemach(data, sshc, sshp, FALSE);
else
result = status;
- Curl_safefree(sshp->path);
- curlx_dyn_free(&sshp->readdir);
- curlx_dyn_free(&sshp->readdir_link);
-
if(Curl_pgrsDone(data))
return CURLE_ABORTED_BY_CALLBACK;
static CURLcode scp_done(struct Curl_easy *data, CURLcode status,
bool premature)
{
+ struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN);
(void)premature; /* not used */
- if(!status)
- state(data, SSH_SCP_DONE);
+ if(sshc && !status)
+ myssh_state(data, sshc, SSH_SCP_DONE);
return ssh_done(data, status);
-
}
static ssize_t scp_send(struct Curl_easy *data, int sockindex,
{
ssize_t nwrite;
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
(void)sockindex; /* we only support SCP on the fixed known primary socket */
(void)eos;
+ if(!sshc) {
+ *err = CURLE_FAILED_INIT;
+ return -1;
+ }
/* libssh2_channel_write() returns int! */
nwrite = (ssize_t) libssh2_channel_write(sshc->ssh_channel, mem, len);
- ssh_block2waitfor(data, (nwrite == LIBSSH2_ERROR_EAGAIN));
+ ssh_block2waitfor(data, sshc, (nwrite == LIBSSH2_ERROR_EAGAIN));
if(nwrite == LIBSSH2_ERROR_EAGAIN) {
*err = CURLE_AGAIN;
{
ssize_t nread;
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
(void)sockindex; /* we only support SCP on the fixed known primary socket */
+ if(!sshc) {
+ *err = CURLE_FAILED_INIT;
+ return -1;
+ }
/* libssh2_channel_read() returns int */
nread = (ssize_t) libssh2_channel_read(sshc->ssh_channel, mem, len);
- ssh_block2waitfor(data, (nread == LIBSSH2_ERROR_EAGAIN));
+ ssh_block2waitfor(data, sshc, (nread == LIBSSH2_ERROR_EAGAIN));
if(nread == LIBSSH2_ERROR_EAGAIN) {
*err = CURLE_AGAIN;
nread = -1;
bool *connected,
bool *dophase_done)
{
+ struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN);
CURLcode result = CURLE_OK;
DEBUGF(infof(data, "DO phase starts"));
*dophase_done = FALSE; /* not done yet */
+ if(!sshc)
+ return CURLE_FAILED_INIT;
/* start the first command in the DO phase */
- state(data, SSH_SFTP_QUOTE_INIT);
+ myssh_state(data, sshc, SSH_SFTP_QUOTE_INIT);
/* run the state-machine */
result = ssh_multi_statemach(data, dophase_done);
struct connectdata *conn, bool dead_connection)
{
CURLcode result = CURLE_OK;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+ struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY);
(void) dead_connection;
DEBUGF(infof(data, "SSH DISCONNECT starts now"));
- if(sshc->ssh_session) {
+ if(sshc && sshc->ssh_session && sshp) {
/* only if there is a session still around to use! */
- state(data, SSH_SFTP_SHUTDOWN);
- result = ssh_block_statemach(data, conn, TRUE);
+ myssh_state(data, sshc, SSH_SFTP_SHUTDOWN);
+ result = ssh_block_statemach(data, sshc, sshp, TRUE);
}
DEBUGF(infof(data, "SSH DISCONNECT is done"));
- sshc_cleanup(sshc, data, TRUE);
+ if(sshc)
+ sshc_cleanup(sshc, data, TRUE);
return result;
bool premature)
{
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+
+ if(!sshc)
+ return CURLE_FAILED_INIT;
if(!status) {
/* Post quote commands are executed after the SFTP_CLOSE state to avoid
operation */
if(!premature && data->set.postquote && !conn->bits.retry)
sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
- state(data, SSH_SFTP_CLOSE);
+ myssh_state(data, sshc, SSH_SFTP_CLOSE);
}
return ssh_done(data, status);
}
{
ssize_t nwrite;
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
(void)sockindex;
(void)eos;
+ if(!sshc) {
+ *err = CURLE_FAILED_INIT;
+ return -1;
+ }
nwrite = libssh2_sftp_write(sshc->sftp_handle, mem, len);
- ssh_block2waitfor(data, (nwrite == LIBSSH2_ERROR_EAGAIN));
+ ssh_block2waitfor(data, sshc, (nwrite == LIBSSH2_ERROR_EAGAIN));
if(nwrite == LIBSSH2_ERROR_EAGAIN) {
*err = CURLE_AGAIN;
{
ssize_t nread;
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
(void)sockindex;
+ if(!sshc) {
+ *err = CURLE_FAILED_INIT;
+ return -1;
+ }
nread = libssh2_sftp_read(sshc->sftp_handle, mem, len);
- ssh_block2waitfor(data, (nread == LIBSSH2_ERROR_EAGAIN));
+ ssh_block2waitfor(data, sshc, (nread == LIBSSH2_ERROR_EAGAIN));
if(nread == LIBSSH2_ERROR_EAGAIN) {
*err = CURLE_AGAIN;
DEBUGASSERT(data);
DEBUGASSERT(conn);
if(conn->handler->protocol & PROTO_FAMILY_SSH) {
- struct ssh_conn *sshc = &conn->proto.sshc;
- if(sshc->ssh_session) {
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+ if(sshc && sshc->ssh_session) {
/* only re-attach if the session already exists */
void **abstract = libssh2_session_abstract(sshc->ssh_session);
*abstract = data;
#include "curl_path.h"
+/* meta key for storing protocol meta at easy handle */
+#define CURL_META_SSH_EASY "meta:proto:ssh:easy"
+/* meta key for storing protocol meta at connection */
+#define CURL_META_SSH_CONN "meta:proto:ssh:conn"
+
/****************************************************************************
* SSH unique setup
***************************************************************************/
#include <limits.h>
#include "../urldata.h"
+#include "../url.h"
#include "../cfilters.h"
#include "../connect.h"
#include "../sendf.h"
curl_socket_t *sock);
static CURLcode wssh_setup_connection(struct Curl_easy *data,
struct connectdata *conn);
-static void wssh_sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data);
+static void wssh_sshc_cleanup(struct ssh_conn *sshc);
#if 0
/*
* SSH State machine related code
*/
/* This is the ONLY way to change SSH state! */
-static void state(struct Curl_easy *data, sshstate nowstate)
+static void wssh_state(struct Curl_easy *data,
+ struct ssh_conn *sshc,
+ sshstate nowstate)
{
- struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
/* for debug purposes */
static const char * const names[] = {
(void *)sshc, names[sshc->state], names[nowstate]);
}
#endif
-
+ (void)data;
sshc->state = nowstate;
}
const void *mem, size_t len, bool eos, CURLcode *err)
{
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
word32 offset[2];
int rc;
(void)sockindex;
(void)eos;
+ if(!sshc) {
+ *err = CURLE_FAILED_INIT;
+ return -1;
+ }
offset[0] = (word32)sshc->offset & 0xFFFFFFFF;
offset[1] = (word32)(sshc->offset >> 32) & 0xFFFFFFFF;
{
int rc;
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
word32 offset[2];
(void)sockindex;
+ if(!sshc) {
+ *err = CURLE_FAILED_INIT;
+ return -1;
+ }
offset[0] = (word32)sshc->offset & 0xFFFFFFFF;
offset[1] = (word32)(sshc->offset >> 32) & 0xFFFFFFFF;
return (ssize_t)rc;
}
+static void wssh_easy_dtor(void *key, size_t klen, void *entry)
+{
+ struct SSHPROTO *sshp = entry;
+ (void)key;
+ (void)klen;
+ Curl_safefree(sshp->path);
+ free(sshp);
+}
+
+static void wssh_conn_dtor(void *key, size_t klen, void *entry)
+{
+ struct ssh_conn *sshc = entry;
+ (void)key;
+ (void)klen;
+ wssh_sshc_cleanup(sshc);
+ free(sshc);
+}
+
/*
* SSH setup and connection
*/
static CURLcode wssh_setup_connection(struct Curl_easy *data,
struct connectdata *conn)
{
- struct SSHPROTO *ssh;
+ struct ssh_conn *sshc;
+ struct SSHPROTO *sshp;
(void)conn;
- data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
- if(!ssh)
+ sshc = calloc(1, sizeof(*sshc));
+ if(!sshc)
+ return CURLE_OUT_OF_MEMORY;
+
+ sshc->initialised = TRUE;
+ if(Curl_conn_meta_set(conn, CURL_META_SSH_CONN, sshc, wssh_conn_dtor))
+ return CURLE_OUT_OF_MEMORY;
+
+ sshp = calloc(1, sizeof(*sshp));
+ if(!sshp ||
+ Curl_meta_set(data, CURL_META_SSH_EASY, sshp, wssh_easy_dtor))
return CURLE_OUT_OF_MEMORY;
return CURLE_OK;
static CURLcode wssh_connect(struct Curl_easy *data, bool *done)
{
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+ struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY);
curl_socket_t sock = conn->sock[FIRSTSOCKET];
int rc;
- /* initialize per-handle data if not already */
- if(!data->req.p.ssh)
- wssh_setup_connection(data, conn);
+ if(!sshc || !sshp)
+ return CURLE_FAILED_INIT;
/* We default to persistent connections. We set this already in this connect
function to make the reuse checks properly be able to check this bit. */
*done = TRUE;
if(conn->handler->protocol & CURLPROTO_SCP)
- state(data, SSH_INIT);
+ wssh_state(data, sshc, SSH_INIT);
else
- state(data, SSH_SFTP_INIT);
+ wssh_state(data, sshc, SSH_SFTP_INIT);
return wssh_multi_statemach(data, done);
error:
- wssh_sshc_cleanup(sshc, data);
+ wssh_sshc_cleanup(sshc);
return CURLE_FAILED_INIT;
}
* wants to be called again when the socket is ready
*/
-static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
+static CURLcode wssh_statemach_act(struct Curl_easy *data,
+ struct ssh_conn *sshc,
+ bool *block)
{
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
- struct SSHPROTO *sftp_scp = data->req.p.ssh;
+ struct SSHPROTO *sftp_scp = Curl_meta_get(data, CURL_META_SSH_EASY);
WS_SFTPNAME *name;
int rc = 0;
*block = FALSE; /* we are not blocking by default */
+ if(!sftp_scp)
+ return CURLE_FAILED_INIT;
+
do {
switch(sshc->state) {
case SSH_INIT:
- state(data, SSH_S_STARTUP);
+ wssh_state(data, sshc, SSH_S_STARTUP);
break;
case SSH_S_STARTUP:
return CURLE_OK;
}
else if(rc != WS_SUCCESS) {
- state(data, SSH_STOP);
+ wssh_state(data, sshc, SSH_STOP);
return CURLE_SSH;
}
infof(data, "wolfssh connected");
- state(data, SSH_STOP);
+ wssh_state(data, sshc, SSH_STOP);
break;
case SSH_STOP:
break;
}
else if(rc == WS_SUCCESS) {
infof(data, "wolfssh SFTP connected");
- state(data, SSH_SFTP_REALPATH);
+ wssh_state(data, sshc, SSH_SFTP_REALPATH);
}
else {
failf(data, "wolfssh SFTP connect error %d", rc);
if(!sshc->homedir)
sshc->actualcode = CURLE_OUT_OF_MEMORY;
wolfSSH_SFTPNAME_list_free(name);
- state(data, SSH_STOP);
+ wssh_state(data, sshc, SSH_STOP);
return CURLE_OK;
}
failf(data, "wolfssh SFTP realpath %d", rc);
result = Curl_getworkingpath(data, sshc->homedir, &sftp_scp->path);
if(result) {
sshc->actualcode = result;
- state(data, SSH_STOP);
+ wssh_state(data, sshc, SSH_STOP);
break;
}
if(data->set.quote) {
infof(data, "Sending quote commands");
sshc->quote_item = data->set.quote;
- state(data, SSH_SFTP_QUOTE);
+ wssh_state(data, sshc, SSH_SFTP_QUOTE);
}
else {
- state(data, SSH_SFTP_GETINFO);
+ wssh_state(data, sshc, SSH_SFTP_GETINFO);
}
break;
case SSH_SFTP_GETINFO:
if(data->set.get_filetime) {
- state(data, SSH_SFTP_FILETIME);
+ wssh_state(data, sshc, SSH_SFTP_FILETIME);
}
else {
- state(data, SSH_SFTP_TRANS_INIT);
+ wssh_state(data, sshc, SSH_SFTP_TRANS_INIT);
}
break;
case SSH_SFTP_TRANS_INIT:
if(data->state.upload)
- state(data, SSH_SFTP_UPLOAD_INIT);
+ wssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT);
else {
if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/')
- state(data, SSH_SFTP_READDIR_INIT);
+ wssh_state(data, sshc, SSH_SFTP_READDIR_INIT);
else
- state(data, SSH_SFTP_DOWNLOAD_INIT);
+ wssh_state(data, sshc, SSH_SFTP_DOWNLOAD_INIT);
}
break;
case SSH_SFTP_UPLOAD_INIT: {
failf(data, "wolfssh SFTP upload open failed: %d", rc);
return CURLE_SSH;
}
- state(data, SSH_SFTP_DOWNLOAD_STAT);
+ wssh_state(data, sshc, SSH_SFTP_DOWNLOAD_STAT);
/* If we have a restart point then we need to seek to the correct
position. */
conn->sockfd = conn->writesockfd;
if(result) {
- state(data, SSH_SFTP_CLOSE);
+ wssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->actualcode = result;
}
else {
timeout here */
Curl_expire(data, 0, EXPIRE_RUN_NOW);
- state(data, SSH_STOP);
+ wssh_state(data, sshc, SSH_STOP);
}
break;
}
}
else if(rc == WS_SUCCESS) {
infof(data, "wolfssh SFTP open succeeded");
- state(data, SSH_SFTP_DOWNLOAD_STAT);
+ wssh_state(data, sshc, SSH_SFTP_DOWNLOAD_STAT);
return CURLE_OK;
}
/* no data to transfer */
Curl_xfer_setup_nop(data);
infof(data, "File already completely downloaded");
- state(data, SSH_STOP);
+ wssh_state(data, sshc, SSH_STOP);
break;
}
Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE);
if(result) {
/* this should never occur; the close state should be entered
at the time the error occurs */
- state(data, SSH_SFTP_CLOSE);
+ wssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->actualcode = result;
}
else {
- state(data, SSH_STOP);
+ wssh_state(data, sshc, SSH_STOP);
}
break;
}
return CURLE_OK;
}
else if(rc == WS_SUCCESS) {
- state(data, SSH_STOP);
+ wssh_state(data, sshc, SSH_STOP);
return CURLE_OK;
}
case SSH_SFTP_READDIR_INIT:
Curl_pgrsSetDownloadSize(data, -1);
if(data->req.no_body) {
- state(data, SSH_STOP);
+ wssh_state(data, sshc, SSH_STOP);
break;
}
- state(data, SSH_SFTP_READDIR);
+ wssh_state(data, sshc, SSH_SFTP_READDIR);
break;
case SSH_SFTP_READDIR:
data->set.list_only ?
name->fName : name->lName);
if(!line) {
- state(data, SSH_SFTP_CLOSE);
+ wssh_state(data, sshc, SSH_SFTP_CLOSE);
sshc->actualcode = CURLE_OUT_OF_MEMORY;
break;
}
name = name->next;
}
wolfSSH_SFTPNAME_list_free(origname);
- state(data, SSH_STOP);
+ wssh_state(data, sshc, SSH_STOP);
return result;
}
failf(data, "wolfssh SFTP ls failed: %d", rc);
return CURLE_SSH;
case SSH_SFTP_SHUTDOWN:
- wssh_sshc_cleanup(sshc, data);
- state(data, SSH_STOP);
+ wssh_sshc_cleanup(sshc);
+ wssh_state(data, sshc, SSH_STOP);
return CURLE_OK;
default:
break;
static CURLcode wssh_multi_statemach(struct Curl_easy *data, bool *done)
{
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
CURLcode result = CURLE_OK;
bool block; /* we store the status and use that to provide a ssh_getsock()
implementation */
+ if(!sshc)
+ return CURLE_FAILED_INIT;
+
do {
- result = wssh_statemach_act(data, &block);
+ result = wssh_statemach_act(data, sshc, &block);
*done = (sshc->state == SSH_STOP);
/* if there is no error, it is not done and it did not EWOULDBLOCK, then
try again */
static
CURLcode wsftp_perform(struct Curl_easy *data,
+ struct ssh_conn *sshc,
bool *connected,
bool *dophase_done)
{
*dophase_done = FALSE; /* not done yet */
/* start the first command in the DO phase */
- state(data, SSH_SFTP_QUOTE_INIT);
+ wssh_state(data, sshc, SSH_SFTP_QUOTE_INIT);
/* run the state-machine */
result = wssh_multi_statemach(data, dophase_done);
CURLcode result;
bool connected = FALSE;
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
*done = FALSE; /* default to false */
+ if(!sshc)
+ return CURLE_FAILED_INIT;
+
data->req.size = -1; /* make sure this is unknown at this point */
sshc->actualcode = CURLE_OK; /* reset error code */
sshc->secondCreateDirs = 0; /* reset the create dir attempt state
if(conn->handler->protocol & CURLPROTO_SCP)
result = wscp_perform(data, &connected, done);
else
- result = wsftp_perform(data, &connected, done);
+ result = wsftp_perform(data, sshc, &connected, done);
return result;
}
static CURLcode wssh_block_statemach(struct Curl_easy *data,
- bool disconnect)
+ struct ssh_conn *sshc,
+ bool disconnect)
{
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc = &conn->proto.sshc;
CURLcode result = CURLE_OK;
while((sshc->state != SSH_STOP) && !result) {
timediff_t left = 1000;
struct curltime now = curlx_now();
- result = wssh_statemach_act(data, &block);
+ result = wssh_statemach_act(data, sshc, &block);
if(result)
break;
/* generic done function for both SCP and SFTP called from their specific
done functions */
-static CURLcode wssh_done(struct Curl_easy *data, CURLcode status)
+static CURLcode wssh_done(struct Curl_easy *data,
+ struct ssh_conn *sshc,
+ CURLcode status)
{
CURLcode result = CURLE_OK;
- struct SSHPROTO *sftp_scp = data->req.p.ssh;
if(!status) {
/* run the state-machine */
- result = wssh_block_statemach(data, FALSE);
+ result = wssh_block_statemach(data, sshc, FALSE);
}
else
result = status;
- if(sftp_scp)
- Curl_safefree(sftp_scp->path);
if(Curl_pgrsDone(data))
return CURLE_ABORTED_BY_CALLBACK;
return result;
}
-static void wssh_sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data)
+static void wssh_sshc_cleanup(struct ssh_conn *sshc)
{
- (void)data;
if(sshc->ssh_session) {
wolfSSH_free(sshc->ssh_session);
sshc->ssh_session = NULL;
static CURLcode wscp_disconnect(struct Curl_easy *data,
struct connectdata *conn, bool dead_connection)
{
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
CURLcode result = CURLE_OK;
(void)dead_connection;
- wssh_sshc_cleanup(sshc, data);
+ if(sshc)
+ wssh_sshc_cleanup(sshc);
return result;
}
#endif
static CURLcode wsftp_done(struct Curl_easy *data,
CURLcode code, bool premature)
{
+ struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN);
(void)premature;
- state(data, SSH_SFTP_CLOSE);
+ if(!sshc)
+ return CURLE_FAILED_INIT;
+
+ wssh_state(data, sshc, SSH_SFTP_CLOSE);
- return wssh_done(data, code);
+ return wssh_done(data, sshc, code);
}
static CURLcode wsftp_doing(struct Curl_easy *data,
struct connectdata *conn,
bool dead)
{
- struct ssh_conn *sshc = &conn->proto.sshc;
+ struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
CURLcode result = CURLE_OK;
(void)dead;
DEBUGF(infof(data, "SSH DISCONNECT starts now"));
- if(conn->proto.sshc.ssh_session) {
+ if(sshc && sshc->ssh_session) {
/* only if there is a session still around to use! */
- state(data, SSH_SFTP_SHUTDOWN);
- result = wssh_block_statemach(data, TRUE);
+ wssh_state(data, sshc, SSH_SFTP_SHUTDOWN);
+ result = wssh_block_statemach(data, sshc, TRUE);
}
- wssh_sshc_cleanup(sshc, data);
+ if(sshc)
+ wssh_sshc_cleanup(sshc);
DEBUGF(infof(data, "SSH DISCONNECT is done"));
return result;
}