113498266Sopenharmony_ci/***************************************************************************
213498266Sopenharmony_ci *                                  _   _ ____  _
313498266Sopenharmony_ci *  Project                     ___| | | |  _ \| |
413498266Sopenharmony_ci *                             / __| | | | |_) | |
513498266Sopenharmony_ci *                            | (__| |_| |  _ <| |___
613498266Sopenharmony_ci *                             \___|\___/|_| \_\_____|
713498266Sopenharmony_ci *
813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
913498266Sopenharmony_ci *
1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which
1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms
1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html.
1313498266Sopenharmony_ci *
1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell
1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is
1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file.
1713498266Sopenharmony_ci *
1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
1913498266Sopenharmony_ci * KIND, either express or implied.
2013498266Sopenharmony_ci *
2113498266Sopenharmony_ci * SPDX-License-Identifier: curl
2213498266Sopenharmony_ci *
2313498266Sopenharmony_ci ***************************************************************************/
2413498266Sopenharmony_ci
2513498266Sopenharmony_ci#include "curl_setup.h"
2613498266Sopenharmony_ci
2713498266Sopenharmony_ci#ifdef USE_WOLFSSH
2813498266Sopenharmony_ci
2913498266Sopenharmony_ci#include <limits.h>
3013498266Sopenharmony_ci
3113498266Sopenharmony_ci#include <wolfssh/ssh.h>
3213498266Sopenharmony_ci#include <wolfssh/wolfsftp.h>
3313498266Sopenharmony_ci#include "urldata.h"
3413498266Sopenharmony_ci#include "cfilters.h"
3513498266Sopenharmony_ci#include "connect.h"
3613498266Sopenharmony_ci#include "sendf.h"
3713498266Sopenharmony_ci#include "progress.h"
3813498266Sopenharmony_ci#include "curl_path.h"
3913498266Sopenharmony_ci#include "strtoofft.h"
4013498266Sopenharmony_ci#include "transfer.h"
4113498266Sopenharmony_ci#include "speedcheck.h"
4213498266Sopenharmony_ci#include "select.h"
4313498266Sopenharmony_ci#include "multiif.h"
4413498266Sopenharmony_ci#include "warnless.h"
4513498266Sopenharmony_ci#include "strdup.h"
4613498266Sopenharmony_ci
4713498266Sopenharmony_ci/* The last 3 #include files should be in this order */
4813498266Sopenharmony_ci#include "curl_printf.h"
4913498266Sopenharmony_ci#include "curl_memory.h"
5013498266Sopenharmony_ci#include "memdebug.h"
5113498266Sopenharmony_ci
5213498266Sopenharmony_cistatic CURLcode wssh_connect(struct Curl_easy *data, bool *done);
5313498266Sopenharmony_cistatic CURLcode wssh_multi_statemach(struct Curl_easy *data, bool *done);
5413498266Sopenharmony_cistatic CURLcode wssh_do(struct Curl_easy *data, bool *done);
5513498266Sopenharmony_ci#if 0
5613498266Sopenharmony_cistatic CURLcode wscp_done(struct Curl_easy *data,
5713498266Sopenharmony_ci                          CURLcode, bool premature);
5813498266Sopenharmony_cistatic CURLcode wscp_doing(struct Curl_easy *data,
5913498266Sopenharmony_ci                           bool *dophase_done);
6013498266Sopenharmony_cistatic CURLcode wscp_disconnect(struct Curl_easy *data,
6113498266Sopenharmony_ci                                struct connectdata *conn,
6213498266Sopenharmony_ci                                bool dead_connection);
6313498266Sopenharmony_ci#endif
6413498266Sopenharmony_cistatic CURLcode wsftp_done(struct Curl_easy *data,
6513498266Sopenharmony_ci                           CURLcode, bool premature);
6613498266Sopenharmony_cistatic CURLcode wsftp_doing(struct Curl_easy *data,
6713498266Sopenharmony_ci                            bool *dophase_done);
6813498266Sopenharmony_cistatic CURLcode wsftp_disconnect(struct Curl_easy *data,
6913498266Sopenharmony_ci                                 struct connectdata *conn,
7013498266Sopenharmony_ci                                 bool dead);
7113498266Sopenharmony_cistatic int wssh_getsock(struct Curl_easy *data,
7213498266Sopenharmony_ci                        struct connectdata *conn,
7313498266Sopenharmony_ci                        curl_socket_t *sock);
7413498266Sopenharmony_cistatic CURLcode wssh_setup_connection(struct Curl_easy *data,
7513498266Sopenharmony_ci                                      struct connectdata *conn);
7613498266Sopenharmony_ci
7713498266Sopenharmony_ci#if 0
7813498266Sopenharmony_ci/*
7913498266Sopenharmony_ci * SCP protocol handler.
8013498266Sopenharmony_ci */
8113498266Sopenharmony_ci
8213498266Sopenharmony_ciconst struct Curl_handler Curl_handler_scp = {
8313498266Sopenharmony_ci  "SCP",                                /* scheme */
8413498266Sopenharmony_ci  wssh_setup_connection,                /* setup_connection */
8513498266Sopenharmony_ci  wssh_do,                              /* do_it */
8613498266Sopenharmony_ci  wscp_done,                            /* done */
8713498266Sopenharmony_ci  ZERO_NULL,                            /* do_more */
8813498266Sopenharmony_ci  wssh_connect,                         /* connect_it */
8913498266Sopenharmony_ci  wssh_multi_statemach,                 /* connecting */
9013498266Sopenharmony_ci  wscp_doing,                           /* doing */
9113498266Sopenharmony_ci  wssh_getsock,                         /* proto_getsock */
9213498266Sopenharmony_ci  wssh_getsock,                         /* doing_getsock */
9313498266Sopenharmony_ci  ZERO_NULL,                            /* domore_getsock */
9413498266Sopenharmony_ci  wssh_getsock,                         /* perform_getsock */
9513498266Sopenharmony_ci  wscp_disconnect,                      /* disconnect */
9613498266Sopenharmony_ci  ZERO_NULL,                            /* write_resp */
9713498266Sopenharmony_ci  ZERO_NULL,                            /* connection_check */
9813498266Sopenharmony_ci  ZERO_NULL,                            /* attach connection */
9913498266Sopenharmony_ci  PORT_SSH,                             /* defport */
10013498266Sopenharmony_ci  CURLPROTO_SCP,                        /* protocol */
10113498266Sopenharmony_ci  PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
10213498266Sopenharmony_ci  | PROTOPT_NOURLQUERY                  /* flags */
10313498266Sopenharmony_ci};
10413498266Sopenharmony_ci
10513498266Sopenharmony_ci#endif
10613498266Sopenharmony_ci
10713498266Sopenharmony_ci/*
10813498266Sopenharmony_ci * SFTP protocol handler.
10913498266Sopenharmony_ci */
11013498266Sopenharmony_ci
11113498266Sopenharmony_ciconst struct Curl_handler Curl_handler_sftp = {
11213498266Sopenharmony_ci  "SFTP",                               /* scheme */
11313498266Sopenharmony_ci  wssh_setup_connection,                /* setup_connection */
11413498266Sopenharmony_ci  wssh_do,                              /* do_it */
11513498266Sopenharmony_ci  wsftp_done,                           /* done */
11613498266Sopenharmony_ci  ZERO_NULL,                            /* do_more */
11713498266Sopenharmony_ci  wssh_connect,                         /* connect_it */
11813498266Sopenharmony_ci  wssh_multi_statemach,                 /* connecting */
11913498266Sopenharmony_ci  wsftp_doing,                          /* doing */
12013498266Sopenharmony_ci  wssh_getsock,                         /* proto_getsock */
12113498266Sopenharmony_ci  wssh_getsock,                         /* doing_getsock */
12213498266Sopenharmony_ci  ZERO_NULL,                            /* domore_getsock */
12313498266Sopenharmony_ci  wssh_getsock,                         /* perform_getsock */
12413498266Sopenharmony_ci  wsftp_disconnect,                     /* disconnect */
12513498266Sopenharmony_ci  ZERO_NULL,                            /* write_resp */
12613498266Sopenharmony_ci  ZERO_NULL,                            /* connection_check */
12713498266Sopenharmony_ci  ZERO_NULL,                            /* attach connection */
12813498266Sopenharmony_ci  PORT_SSH,                             /* defport */
12913498266Sopenharmony_ci  CURLPROTO_SFTP,                       /* protocol */
13013498266Sopenharmony_ci  CURLPROTO_SFTP,                       /* family */
13113498266Sopenharmony_ci  PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
13213498266Sopenharmony_ci  | PROTOPT_NOURLQUERY                  /* flags */
13313498266Sopenharmony_ci};
13413498266Sopenharmony_ci
13513498266Sopenharmony_ci/*
13613498266Sopenharmony_ci * SSH State machine related code
13713498266Sopenharmony_ci */
13813498266Sopenharmony_ci/* This is the ONLY way to change SSH state! */
13913498266Sopenharmony_cistatic void state(struct Curl_easy *data, sshstate nowstate)
14013498266Sopenharmony_ci{
14113498266Sopenharmony_ci  struct connectdata *conn = data->conn;
14213498266Sopenharmony_ci  struct ssh_conn *sshc = &conn->proto.sshc;
14313498266Sopenharmony_ci#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
14413498266Sopenharmony_ci  /* for debug purposes */
14513498266Sopenharmony_ci  static const char * const names[] = {
14613498266Sopenharmony_ci    "SSH_STOP",
14713498266Sopenharmony_ci    "SSH_INIT",
14813498266Sopenharmony_ci    "SSH_S_STARTUP",
14913498266Sopenharmony_ci    "SSH_HOSTKEY",
15013498266Sopenharmony_ci    "SSH_AUTHLIST",
15113498266Sopenharmony_ci    "SSH_AUTH_PKEY_INIT",
15213498266Sopenharmony_ci    "SSH_AUTH_PKEY",
15313498266Sopenharmony_ci    "SSH_AUTH_PASS_INIT",
15413498266Sopenharmony_ci    "SSH_AUTH_PASS",
15513498266Sopenharmony_ci    "SSH_AUTH_AGENT_INIT",
15613498266Sopenharmony_ci    "SSH_AUTH_AGENT_LIST",
15713498266Sopenharmony_ci    "SSH_AUTH_AGENT",
15813498266Sopenharmony_ci    "SSH_AUTH_HOST_INIT",
15913498266Sopenharmony_ci    "SSH_AUTH_HOST",
16013498266Sopenharmony_ci    "SSH_AUTH_KEY_INIT",
16113498266Sopenharmony_ci    "SSH_AUTH_KEY",
16213498266Sopenharmony_ci    "SSH_AUTH_GSSAPI",
16313498266Sopenharmony_ci    "SSH_AUTH_DONE",
16413498266Sopenharmony_ci    "SSH_SFTP_INIT",
16513498266Sopenharmony_ci    "SSH_SFTP_REALPATH",
16613498266Sopenharmony_ci    "SSH_SFTP_QUOTE_INIT",
16713498266Sopenharmony_ci    "SSH_SFTP_POSTQUOTE_INIT",
16813498266Sopenharmony_ci    "SSH_SFTP_QUOTE",
16913498266Sopenharmony_ci    "SSH_SFTP_NEXT_QUOTE",
17013498266Sopenharmony_ci    "SSH_SFTP_QUOTE_STAT",
17113498266Sopenharmony_ci    "SSH_SFTP_QUOTE_SETSTAT",
17213498266Sopenharmony_ci    "SSH_SFTP_QUOTE_SYMLINK",
17313498266Sopenharmony_ci    "SSH_SFTP_QUOTE_MKDIR",
17413498266Sopenharmony_ci    "SSH_SFTP_QUOTE_RENAME",
17513498266Sopenharmony_ci    "SSH_SFTP_QUOTE_RMDIR",
17613498266Sopenharmony_ci    "SSH_SFTP_QUOTE_UNLINK",
17713498266Sopenharmony_ci    "SSH_SFTP_QUOTE_STATVFS",
17813498266Sopenharmony_ci    "SSH_SFTP_GETINFO",
17913498266Sopenharmony_ci    "SSH_SFTP_FILETIME",
18013498266Sopenharmony_ci    "SSH_SFTP_TRANS_INIT",
18113498266Sopenharmony_ci    "SSH_SFTP_UPLOAD_INIT",
18213498266Sopenharmony_ci    "SSH_SFTP_CREATE_DIRS_INIT",
18313498266Sopenharmony_ci    "SSH_SFTP_CREATE_DIRS",
18413498266Sopenharmony_ci    "SSH_SFTP_CREATE_DIRS_MKDIR",
18513498266Sopenharmony_ci    "SSH_SFTP_READDIR_INIT",
18613498266Sopenharmony_ci    "SSH_SFTP_READDIR",
18713498266Sopenharmony_ci    "SSH_SFTP_READDIR_LINK",
18813498266Sopenharmony_ci    "SSH_SFTP_READDIR_BOTTOM",
18913498266Sopenharmony_ci    "SSH_SFTP_READDIR_DONE",
19013498266Sopenharmony_ci    "SSH_SFTP_DOWNLOAD_INIT",
19113498266Sopenharmony_ci    "SSH_SFTP_DOWNLOAD_STAT",
19213498266Sopenharmony_ci    "SSH_SFTP_CLOSE",
19313498266Sopenharmony_ci    "SSH_SFTP_SHUTDOWN",
19413498266Sopenharmony_ci    "SSH_SCP_TRANS_INIT",
19513498266Sopenharmony_ci    "SSH_SCP_UPLOAD_INIT",
19613498266Sopenharmony_ci    "SSH_SCP_DOWNLOAD_INIT",
19713498266Sopenharmony_ci    "SSH_SCP_DOWNLOAD",
19813498266Sopenharmony_ci    "SSH_SCP_DONE",
19913498266Sopenharmony_ci    "SSH_SCP_SEND_EOF",
20013498266Sopenharmony_ci    "SSH_SCP_WAIT_EOF",
20113498266Sopenharmony_ci    "SSH_SCP_WAIT_CLOSE",
20213498266Sopenharmony_ci    "SSH_SCP_CHANNEL_FREE",
20313498266Sopenharmony_ci    "SSH_SESSION_DISCONNECT",
20413498266Sopenharmony_ci    "SSH_SESSION_FREE",
20513498266Sopenharmony_ci    "QUIT"
20613498266Sopenharmony_ci  };
20713498266Sopenharmony_ci
20813498266Sopenharmony_ci  /* a precaution to make sure the lists are in sync */
20913498266Sopenharmony_ci  DEBUGASSERT(sizeof(names)/sizeof(names[0]) == SSH_LAST);
21013498266Sopenharmony_ci
21113498266Sopenharmony_ci  if(sshc->state != nowstate) {
21213498266Sopenharmony_ci    infof(data, "wolfssh %p state change from %s to %s",
21313498266Sopenharmony_ci          (void *)sshc, names[sshc->state], names[nowstate]);
21413498266Sopenharmony_ci  }
21513498266Sopenharmony_ci#endif
21613498266Sopenharmony_ci
21713498266Sopenharmony_ci  sshc->state = nowstate;
21813498266Sopenharmony_ci}
21913498266Sopenharmony_ci
22013498266Sopenharmony_cistatic ssize_t wscp_send(struct Curl_easy *data, int sockindex,
22113498266Sopenharmony_ci                         const void *mem, size_t len, CURLcode *err)
22213498266Sopenharmony_ci{
22313498266Sopenharmony_ci  ssize_t nwrite = 0;
22413498266Sopenharmony_ci  (void)data;
22513498266Sopenharmony_ci  (void)sockindex; /* we only support SCP on the fixed known primary socket */
22613498266Sopenharmony_ci  (void)mem;
22713498266Sopenharmony_ci  (void)len;
22813498266Sopenharmony_ci  (void)err;
22913498266Sopenharmony_ci
23013498266Sopenharmony_ci  return nwrite;
23113498266Sopenharmony_ci}
23213498266Sopenharmony_ci
23313498266Sopenharmony_cistatic ssize_t wscp_recv(struct Curl_easy *data, int sockindex,
23413498266Sopenharmony_ci                         char *mem, size_t len, CURLcode *err)
23513498266Sopenharmony_ci{
23613498266Sopenharmony_ci  ssize_t nread = 0;
23713498266Sopenharmony_ci  (void)data;
23813498266Sopenharmony_ci  (void)sockindex; /* we only support SCP on the fixed known primary socket */
23913498266Sopenharmony_ci  (void)mem;
24013498266Sopenharmony_ci  (void)len;
24113498266Sopenharmony_ci  (void)err;
24213498266Sopenharmony_ci
24313498266Sopenharmony_ci  return nread;
24413498266Sopenharmony_ci}
24513498266Sopenharmony_ci
24613498266Sopenharmony_ci/* return number of sent bytes */
24713498266Sopenharmony_cistatic ssize_t wsftp_send(struct Curl_easy *data, int sockindex,
24813498266Sopenharmony_ci                          const void *mem, size_t len, CURLcode *err)
24913498266Sopenharmony_ci{
25013498266Sopenharmony_ci  struct connectdata *conn = data->conn;
25113498266Sopenharmony_ci  struct ssh_conn *sshc = &conn->proto.sshc;
25213498266Sopenharmony_ci  word32 offset[2];
25313498266Sopenharmony_ci  int rc;
25413498266Sopenharmony_ci  (void)sockindex;
25513498266Sopenharmony_ci
25613498266Sopenharmony_ci  offset[0] = (word32)sshc->offset&0xFFFFFFFF;
25713498266Sopenharmony_ci  offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF;
25813498266Sopenharmony_ci
25913498266Sopenharmony_ci  rc = wolfSSH_SFTP_SendWritePacket(sshc->ssh_session, sshc->handle,
26013498266Sopenharmony_ci                                    sshc->handleSz,
26113498266Sopenharmony_ci                                    &offset[0],
26213498266Sopenharmony_ci                                    (byte *)mem, (word32)len);
26313498266Sopenharmony_ci
26413498266Sopenharmony_ci  if(rc == WS_FATAL_ERROR)
26513498266Sopenharmony_ci    rc = wolfSSH_get_error(sshc->ssh_session);
26613498266Sopenharmony_ci  if(rc == WS_WANT_READ) {
26713498266Sopenharmony_ci    conn->waitfor = KEEP_RECV;
26813498266Sopenharmony_ci    *err = CURLE_AGAIN;
26913498266Sopenharmony_ci    return -1;
27013498266Sopenharmony_ci  }
27113498266Sopenharmony_ci  else if(rc == WS_WANT_WRITE) {
27213498266Sopenharmony_ci    conn->waitfor = KEEP_SEND;
27313498266Sopenharmony_ci    *err = CURLE_AGAIN;
27413498266Sopenharmony_ci    return -1;
27513498266Sopenharmony_ci  }
27613498266Sopenharmony_ci  if(rc < 0) {
27713498266Sopenharmony_ci    failf(data, "wolfSSH_SFTP_SendWritePacket returned %d", rc);
27813498266Sopenharmony_ci    return -1;
27913498266Sopenharmony_ci  }
28013498266Sopenharmony_ci  DEBUGASSERT(rc == (int)len);
28113498266Sopenharmony_ci  infof(data, "sent %zu bytes SFTP from offset %" CURL_FORMAT_CURL_OFF_T,
28213498266Sopenharmony_ci        len, sshc->offset);
28313498266Sopenharmony_ci  sshc->offset += len;
28413498266Sopenharmony_ci  return (ssize_t)rc;
28513498266Sopenharmony_ci}
28613498266Sopenharmony_ci
28713498266Sopenharmony_ci/*
28813498266Sopenharmony_ci * Return number of received (decrypted) bytes
28913498266Sopenharmony_ci * or <0 on error
29013498266Sopenharmony_ci */
29113498266Sopenharmony_cistatic ssize_t wsftp_recv(struct Curl_easy *data, int sockindex,
29213498266Sopenharmony_ci                          char *mem, size_t len, CURLcode *err)
29313498266Sopenharmony_ci{
29413498266Sopenharmony_ci  int rc;
29513498266Sopenharmony_ci  struct connectdata *conn = data->conn;
29613498266Sopenharmony_ci  struct ssh_conn *sshc = &conn->proto.sshc;
29713498266Sopenharmony_ci  word32 offset[2];
29813498266Sopenharmony_ci  (void)sockindex;
29913498266Sopenharmony_ci
30013498266Sopenharmony_ci  offset[0] = (word32)sshc->offset&0xFFFFFFFF;
30113498266Sopenharmony_ci  offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF;
30213498266Sopenharmony_ci
30313498266Sopenharmony_ci  rc = wolfSSH_SFTP_SendReadPacket(sshc->ssh_session, sshc->handle,
30413498266Sopenharmony_ci                                   sshc->handleSz,
30513498266Sopenharmony_ci                                   &offset[0],
30613498266Sopenharmony_ci                                   (byte *)mem, (word32)len);
30713498266Sopenharmony_ci  if(rc == WS_FATAL_ERROR)
30813498266Sopenharmony_ci    rc = wolfSSH_get_error(sshc->ssh_session);
30913498266Sopenharmony_ci  if(rc == WS_WANT_READ) {
31013498266Sopenharmony_ci    conn->waitfor = KEEP_RECV;
31113498266Sopenharmony_ci    *err = CURLE_AGAIN;
31213498266Sopenharmony_ci    return -1;
31313498266Sopenharmony_ci  }
31413498266Sopenharmony_ci  else if(rc == WS_WANT_WRITE) {
31513498266Sopenharmony_ci    conn->waitfor = KEEP_SEND;
31613498266Sopenharmony_ci    *err = CURLE_AGAIN;
31713498266Sopenharmony_ci    return -1;
31813498266Sopenharmony_ci  }
31913498266Sopenharmony_ci
32013498266Sopenharmony_ci  DEBUGASSERT(rc <= (int)len);
32113498266Sopenharmony_ci
32213498266Sopenharmony_ci  if(rc < 0) {
32313498266Sopenharmony_ci    failf(data, "wolfSSH_SFTP_SendReadPacket returned %d", rc);
32413498266Sopenharmony_ci    return -1;
32513498266Sopenharmony_ci  }
32613498266Sopenharmony_ci  sshc->offset += len;
32713498266Sopenharmony_ci
32813498266Sopenharmony_ci  return (ssize_t)rc;
32913498266Sopenharmony_ci}
33013498266Sopenharmony_ci
33113498266Sopenharmony_ci/*
33213498266Sopenharmony_ci * SSH setup and connection
33313498266Sopenharmony_ci */
33413498266Sopenharmony_cistatic CURLcode wssh_setup_connection(struct Curl_easy *data,
33513498266Sopenharmony_ci                                      struct connectdata *conn)
33613498266Sopenharmony_ci{
33713498266Sopenharmony_ci  struct SSHPROTO *ssh;
33813498266Sopenharmony_ci  (void)conn;
33913498266Sopenharmony_ci
34013498266Sopenharmony_ci  data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
34113498266Sopenharmony_ci  if(!ssh)
34213498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
34313498266Sopenharmony_ci
34413498266Sopenharmony_ci  return CURLE_OK;
34513498266Sopenharmony_ci}
34613498266Sopenharmony_ci
34713498266Sopenharmony_cistatic int userauth(byte authtype,
34813498266Sopenharmony_ci                    WS_UserAuthData* authdata,
34913498266Sopenharmony_ci                    void *ctx)
35013498266Sopenharmony_ci{
35113498266Sopenharmony_ci  struct Curl_easy *data = ctx;
35213498266Sopenharmony_ci  DEBUGF(infof(data, "wolfssh callback: type %s",
35313498266Sopenharmony_ci               authtype == WOLFSSH_USERAUTH_PASSWORD ? "PASSWORD" :
35413498266Sopenharmony_ci               "PUBLICCKEY"));
35513498266Sopenharmony_ci  if(authtype == WOLFSSH_USERAUTH_PASSWORD) {
35613498266Sopenharmony_ci    authdata->sf.password.password = (byte *)data->conn->passwd;
35713498266Sopenharmony_ci    authdata->sf.password.passwordSz = (word32) strlen(data->conn->passwd);
35813498266Sopenharmony_ci  }
35913498266Sopenharmony_ci
36013498266Sopenharmony_ci  return 0;
36113498266Sopenharmony_ci}
36213498266Sopenharmony_ci
36313498266Sopenharmony_cistatic CURLcode wssh_connect(struct Curl_easy *data, bool *done)
36413498266Sopenharmony_ci{
36513498266Sopenharmony_ci  struct connectdata *conn = data->conn;
36613498266Sopenharmony_ci  struct ssh_conn *sshc;
36713498266Sopenharmony_ci  curl_socket_t sock = conn->sock[FIRSTSOCKET];
36813498266Sopenharmony_ci  int rc;
36913498266Sopenharmony_ci
37013498266Sopenharmony_ci  /* initialize per-handle data if not already */
37113498266Sopenharmony_ci  if(!data->req.p.ssh)
37213498266Sopenharmony_ci    wssh_setup_connection(data, conn);
37313498266Sopenharmony_ci
37413498266Sopenharmony_ci  /* We default to persistent connections. We set this already in this connect
37513498266Sopenharmony_ci     function to make the reuse checks properly be able to check this bit. */
37613498266Sopenharmony_ci  connkeep(conn, "SSH default");
37713498266Sopenharmony_ci
37813498266Sopenharmony_ci  if(conn->handler->protocol & CURLPROTO_SCP) {
37913498266Sopenharmony_ci    conn->recv[FIRSTSOCKET] = wscp_recv;
38013498266Sopenharmony_ci    conn->send[FIRSTSOCKET] = wscp_send;
38113498266Sopenharmony_ci  }
38213498266Sopenharmony_ci  else {
38313498266Sopenharmony_ci    conn->recv[FIRSTSOCKET] = wsftp_recv;
38413498266Sopenharmony_ci    conn->send[FIRSTSOCKET] = wsftp_send;
38513498266Sopenharmony_ci  }
38613498266Sopenharmony_ci  sshc = &conn->proto.sshc;
38713498266Sopenharmony_ci  sshc->ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL);
38813498266Sopenharmony_ci  if(!sshc->ctx) {
38913498266Sopenharmony_ci    failf(data, "No wolfSSH context");
39013498266Sopenharmony_ci    goto error;
39113498266Sopenharmony_ci  }
39213498266Sopenharmony_ci
39313498266Sopenharmony_ci  sshc->ssh_session = wolfSSH_new(sshc->ctx);
39413498266Sopenharmony_ci  if(!sshc->ssh_session) {
39513498266Sopenharmony_ci    failf(data, "No wolfSSH session");
39613498266Sopenharmony_ci    goto error;
39713498266Sopenharmony_ci  }
39813498266Sopenharmony_ci
39913498266Sopenharmony_ci  rc = wolfSSH_SetUsername(sshc->ssh_session, conn->user);
40013498266Sopenharmony_ci  if(rc != WS_SUCCESS) {
40113498266Sopenharmony_ci    failf(data, "wolfSSH failed to set user name");
40213498266Sopenharmony_ci    goto error;
40313498266Sopenharmony_ci  }
40413498266Sopenharmony_ci
40513498266Sopenharmony_ci  /* set callback for authentication */
40613498266Sopenharmony_ci  wolfSSH_SetUserAuth(sshc->ctx, userauth);
40713498266Sopenharmony_ci  wolfSSH_SetUserAuthCtx(sshc->ssh_session, data);
40813498266Sopenharmony_ci
40913498266Sopenharmony_ci  rc = wolfSSH_set_fd(sshc->ssh_session, (int)sock);
41013498266Sopenharmony_ci  if(rc) {
41113498266Sopenharmony_ci    failf(data, "wolfSSH failed to set socket");
41213498266Sopenharmony_ci    goto error;
41313498266Sopenharmony_ci  }
41413498266Sopenharmony_ci
41513498266Sopenharmony_ci#if 0
41613498266Sopenharmony_ci  wolfSSH_Debugging_ON();
41713498266Sopenharmony_ci#endif
41813498266Sopenharmony_ci
41913498266Sopenharmony_ci  *done = TRUE;
42013498266Sopenharmony_ci  if(conn->handler->protocol & CURLPROTO_SCP)
42113498266Sopenharmony_ci    state(data, SSH_INIT);
42213498266Sopenharmony_ci  else
42313498266Sopenharmony_ci    state(data, SSH_SFTP_INIT);
42413498266Sopenharmony_ci
42513498266Sopenharmony_ci  return wssh_multi_statemach(data, done);
42613498266Sopenharmony_cierror:
42713498266Sopenharmony_ci  wolfSSH_free(sshc->ssh_session);
42813498266Sopenharmony_ci  wolfSSH_CTX_free(sshc->ctx);
42913498266Sopenharmony_ci  return CURLE_FAILED_INIT;
43013498266Sopenharmony_ci}
43113498266Sopenharmony_ci
43213498266Sopenharmony_ci/*
43313498266Sopenharmony_ci * wssh_statemach_act() runs the SSH state machine as far as it can without
43413498266Sopenharmony_ci * blocking and without reaching the end.  The data the pointer 'block' points
43513498266Sopenharmony_ci * to will be set to TRUE if the wolfssh function returns EAGAIN meaning it
43613498266Sopenharmony_ci * wants to be called again when the socket is ready
43713498266Sopenharmony_ci */
43813498266Sopenharmony_ci
43913498266Sopenharmony_cistatic CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
44013498266Sopenharmony_ci{
44113498266Sopenharmony_ci  CURLcode result = CURLE_OK;
44213498266Sopenharmony_ci  struct connectdata *conn = data->conn;
44313498266Sopenharmony_ci  struct ssh_conn *sshc = &conn->proto.sshc;
44413498266Sopenharmony_ci  struct SSHPROTO *sftp_scp = data->req.p.ssh;
44513498266Sopenharmony_ci  WS_SFTPNAME *name;
44613498266Sopenharmony_ci  int rc = 0;
44713498266Sopenharmony_ci  *block = FALSE; /* we're not blocking by default */
44813498266Sopenharmony_ci
44913498266Sopenharmony_ci  do {
45013498266Sopenharmony_ci    switch(sshc->state) {
45113498266Sopenharmony_ci    case SSH_INIT:
45213498266Sopenharmony_ci      state(data, SSH_S_STARTUP);
45313498266Sopenharmony_ci      break;
45413498266Sopenharmony_ci
45513498266Sopenharmony_ci    case SSH_S_STARTUP:
45613498266Sopenharmony_ci      rc = wolfSSH_connect(sshc->ssh_session);
45713498266Sopenharmony_ci      if(rc != WS_SUCCESS)
45813498266Sopenharmony_ci        rc = wolfSSH_get_error(sshc->ssh_session);
45913498266Sopenharmony_ci      if(rc == WS_WANT_READ) {
46013498266Sopenharmony_ci        *block = TRUE;
46113498266Sopenharmony_ci        conn->waitfor = KEEP_RECV;
46213498266Sopenharmony_ci        return CURLE_OK;
46313498266Sopenharmony_ci      }
46413498266Sopenharmony_ci      else if(rc == WS_WANT_WRITE) {
46513498266Sopenharmony_ci        *block = TRUE;
46613498266Sopenharmony_ci        conn->waitfor = KEEP_SEND;
46713498266Sopenharmony_ci        return CURLE_OK;
46813498266Sopenharmony_ci      }
46913498266Sopenharmony_ci      else if(rc != WS_SUCCESS) {
47013498266Sopenharmony_ci        state(data, SSH_STOP);
47113498266Sopenharmony_ci        return CURLE_SSH;
47213498266Sopenharmony_ci      }
47313498266Sopenharmony_ci      infof(data, "wolfssh connected");
47413498266Sopenharmony_ci      state(data, SSH_STOP);
47513498266Sopenharmony_ci      break;
47613498266Sopenharmony_ci    case SSH_STOP:
47713498266Sopenharmony_ci      break;
47813498266Sopenharmony_ci
47913498266Sopenharmony_ci    case SSH_SFTP_INIT:
48013498266Sopenharmony_ci      rc = wolfSSH_SFTP_connect(sshc->ssh_session);
48113498266Sopenharmony_ci      if(rc != WS_SUCCESS)
48213498266Sopenharmony_ci        rc = wolfSSH_get_error(sshc->ssh_session);
48313498266Sopenharmony_ci      if(rc == WS_WANT_READ) {
48413498266Sopenharmony_ci        *block = TRUE;
48513498266Sopenharmony_ci        conn->waitfor = KEEP_RECV;
48613498266Sopenharmony_ci        return CURLE_OK;
48713498266Sopenharmony_ci      }
48813498266Sopenharmony_ci      else if(rc == WS_WANT_WRITE) {
48913498266Sopenharmony_ci        *block = TRUE;
49013498266Sopenharmony_ci        conn->waitfor = KEEP_SEND;
49113498266Sopenharmony_ci        return CURLE_OK;
49213498266Sopenharmony_ci      }
49313498266Sopenharmony_ci      else if(rc == WS_SUCCESS) {
49413498266Sopenharmony_ci        infof(data, "wolfssh SFTP connected");
49513498266Sopenharmony_ci        state(data, SSH_SFTP_REALPATH);
49613498266Sopenharmony_ci      }
49713498266Sopenharmony_ci      else {
49813498266Sopenharmony_ci        failf(data, "wolfssh SFTP connect error %d", rc);
49913498266Sopenharmony_ci        return CURLE_SSH;
50013498266Sopenharmony_ci      }
50113498266Sopenharmony_ci      break;
50213498266Sopenharmony_ci    case SSH_SFTP_REALPATH:
50313498266Sopenharmony_ci      name = wolfSSH_SFTP_RealPath(sshc->ssh_session, (char *)".");
50413498266Sopenharmony_ci      rc = wolfSSH_get_error(sshc->ssh_session);
50513498266Sopenharmony_ci      if(rc == WS_WANT_READ) {
50613498266Sopenharmony_ci        *block = TRUE;
50713498266Sopenharmony_ci        conn->waitfor = KEEP_RECV;
50813498266Sopenharmony_ci        return CURLE_OK;
50913498266Sopenharmony_ci      }
51013498266Sopenharmony_ci      else if(rc == WS_WANT_WRITE) {
51113498266Sopenharmony_ci        *block = TRUE;
51213498266Sopenharmony_ci        conn->waitfor = KEEP_SEND;
51313498266Sopenharmony_ci        return CURLE_OK;
51413498266Sopenharmony_ci      }
51513498266Sopenharmony_ci      else if(name && (rc == WS_SUCCESS)) {
51613498266Sopenharmony_ci        sshc->homedir = Curl_memdup0(name->fName, name->fSz);
51713498266Sopenharmony_ci        if(!sshc->homedir)
51813498266Sopenharmony_ci          sshc->actualcode = CURLE_OUT_OF_MEMORY;
51913498266Sopenharmony_ci        wolfSSH_SFTPNAME_list_free(name);
52013498266Sopenharmony_ci        state(data, SSH_STOP);
52113498266Sopenharmony_ci        return CURLE_OK;
52213498266Sopenharmony_ci      }
52313498266Sopenharmony_ci      failf(data, "wolfssh SFTP realpath %d", rc);
52413498266Sopenharmony_ci      return CURLE_SSH;
52513498266Sopenharmony_ci
52613498266Sopenharmony_ci    case SSH_SFTP_QUOTE_INIT:
52713498266Sopenharmony_ci      result = Curl_getworkingpath(data, sshc->homedir, &sftp_scp->path);
52813498266Sopenharmony_ci      if(result) {
52913498266Sopenharmony_ci        sshc->actualcode = result;
53013498266Sopenharmony_ci        state(data, SSH_STOP);
53113498266Sopenharmony_ci        break;
53213498266Sopenharmony_ci      }
53313498266Sopenharmony_ci
53413498266Sopenharmony_ci      if(data->set.quote) {
53513498266Sopenharmony_ci        infof(data, "Sending quote commands");
53613498266Sopenharmony_ci        sshc->quote_item = data->set.quote;
53713498266Sopenharmony_ci        state(data, SSH_SFTP_QUOTE);
53813498266Sopenharmony_ci      }
53913498266Sopenharmony_ci      else {
54013498266Sopenharmony_ci        state(data, SSH_SFTP_GETINFO);
54113498266Sopenharmony_ci      }
54213498266Sopenharmony_ci      break;
54313498266Sopenharmony_ci    case SSH_SFTP_GETINFO:
54413498266Sopenharmony_ci      if(data->set.get_filetime) {
54513498266Sopenharmony_ci        state(data, SSH_SFTP_FILETIME);
54613498266Sopenharmony_ci      }
54713498266Sopenharmony_ci      else {
54813498266Sopenharmony_ci        state(data, SSH_SFTP_TRANS_INIT);
54913498266Sopenharmony_ci      }
55013498266Sopenharmony_ci      break;
55113498266Sopenharmony_ci    case SSH_SFTP_TRANS_INIT:
55213498266Sopenharmony_ci      if(data->state.upload)
55313498266Sopenharmony_ci        state(data, SSH_SFTP_UPLOAD_INIT);
55413498266Sopenharmony_ci      else {
55513498266Sopenharmony_ci        if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/')
55613498266Sopenharmony_ci          state(data, SSH_SFTP_READDIR_INIT);
55713498266Sopenharmony_ci        else
55813498266Sopenharmony_ci          state(data, SSH_SFTP_DOWNLOAD_INIT);
55913498266Sopenharmony_ci      }
56013498266Sopenharmony_ci      break;
56113498266Sopenharmony_ci    case SSH_SFTP_UPLOAD_INIT: {
56213498266Sopenharmony_ci      word32 flags;
56313498266Sopenharmony_ci      WS_SFTP_FILEATRB createattrs;
56413498266Sopenharmony_ci      if(data->state.resume_from) {
56513498266Sopenharmony_ci        WS_SFTP_FILEATRB attrs;
56613498266Sopenharmony_ci        if(data->state.resume_from < 0) {
56713498266Sopenharmony_ci          rc = wolfSSH_SFTP_STAT(sshc->ssh_session, sftp_scp->path,
56813498266Sopenharmony_ci                                 &attrs);
56913498266Sopenharmony_ci          if(rc != WS_SUCCESS)
57013498266Sopenharmony_ci            break;
57113498266Sopenharmony_ci
57213498266Sopenharmony_ci          if(rc) {
57313498266Sopenharmony_ci            data->state.resume_from = 0;
57413498266Sopenharmony_ci          }
57513498266Sopenharmony_ci          else {
57613498266Sopenharmony_ci            curl_off_t size = ((curl_off_t)attrs.sz[1] << 32) | attrs.sz[0];
57713498266Sopenharmony_ci            if(size < 0) {
57813498266Sopenharmony_ci              failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
57913498266Sopenharmony_ci              return CURLE_BAD_DOWNLOAD_RESUME;
58013498266Sopenharmony_ci            }
58113498266Sopenharmony_ci            data->state.resume_from = size;
58213498266Sopenharmony_ci          }
58313498266Sopenharmony_ci        }
58413498266Sopenharmony_ci      }
58513498266Sopenharmony_ci
58613498266Sopenharmony_ci      if(data->set.remote_append)
58713498266Sopenharmony_ci        /* Try to open for append, but create if nonexisting */
58813498266Sopenharmony_ci        flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_APPEND;
58913498266Sopenharmony_ci      else if(data->state.resume_from > 0)
59013498266Sopenharmony_ci        /* If we have restart position then open for append */
59113498266Sopenharmony_ci        flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_APPEND;
59213498266Sopenharmony_ci      else
59313498266Sopenharmony_ci        /* Clear file before writing (normal behavior) */
59413498266Sopenharmony_ci        flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_TRUNC;
59513498266Sopenharmony_ci
59613498266Sopenharmony_ci      memset(&createattrs, 0, sizeof(createattrs));
59713498266Sopenharmony_ci      createattrs.per = (word32)data->set.new_file_perms;
59813498266Sopenharmony_ci      sshc->handleSz = sizeof(sshc->handle);
59913498266Sopenharmony_ci      rc = wolfSSH_SFTP_Open(sshc->ssh_session, sftp_scp->path,
60013498266Sopenharmony_ci                             flags, &createattrs,
60113498266Sopenharmony_ci                             sshc->handle, &sshc->handleSz);
60213498266Sopenharmony_ci      if(rc == WS_FATAL_ERROR)
60313498266Sopenharmony_ci        rc = wolfSSH_get_error(sshc->ssh_session);
60413498266Sopenharmony_ci      if(rc == WS_WANT_READ) {
60513498266Sopenharmony_ci        *block = TRUE;
60613498266Sopenharmony_ci        conn->waitfor = KEEP_RECV;
60713498266Sopenharmony_ci        return CURLE_OK;
60813498266Sopenharmony_ci      }
60913498266Sopenharmony_ci      else if(rc == WS_WANT_WRITE) {
61013498266Sopenharmony_ci        *block = TRUE;
61113498266Sopenharmony_ci        conn->waitfor = KEEP_SEND;
61213498266Sopenharmony_ci        return CURLE_OK;
61313498266Sopenharmony_ci      }
61413498266Sopenharmony_ci      else if(rc == WS_SUCCESS) {
61513498266Sopenharmony_ci        infof(data, "wolfssh SFTP open succeeded");
61613498266Sopenharmony_ci      }
61713498266Sopenharmony_ci      else {
61813498266Sopenharmony_ci        failf(data, "wolfssh SFTP upload open failed: %d", rc);
61913498266Sopenharmony_ci        return CURLE_SSH;
62013498266Sopenharmony_ci      }
62113498266Sopenharmony_ci      state(data, SSH_SFTP_DOWNLOAD_STAT);
62213498266Sopenharmony_ci
62313498266Sopenharmony_ci      /* If we have a restart point then we need to seek to the correct
62413498266Sopenharmony_ci         position. */
62513498266Sopenharmony_ci      if(data->state.resume_from > 0) {
62613498266Sopenharmony_ci        /* Let's read off the proper amount of bytes from the input. */
62713498266Sopenharmony_ci        int seekerr = CURL_SEEKFUNC_OK;
62813498266Sopenharmony_ci        if(conn->seek_func) {
62913498266Sopenharmony_ci          Curl_set_in_callback(data, true);
63013498266Sopenharmony_ci          seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
63113498266Sopenharmony_ci                                    SEEK_SET);
63213498266Sopenharmony_ci          Curl_set_in_callback(data, false);
63313498266Sopenharmony_ci        }
63413498266Sopenharmony_ci
63513498266Sopenharmony_ci        if(seekerr != CURL_SEEKFUNC_OK) {
63613498266Sopenharmony_ci          curl_off_t passed = 0;
63713498266Sopenharmony_ci
63813498266Sopenharmony_ci          if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
63913498266Sopenharmony_ci            failf(data, "Could not seek stream");
64013498266Sopenharmony_ci            return CURLE_FTP_COULDNT_USE_REST;
64113498266Sopenharmony_ci          }
64213498266Sopenharmony_ci          /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
64313498266Sopenharmony_ci          do {
64413498266Sopenharmony_ci            char scratch[4*1024];
64513498266Sopenharmony_ci            size_t readthisamountnow =
64613498266Sopenharmony_ci              (data->state.resume_from - passed >
64713498266Sopenharmony_ci                (curl_off_t)sizeof(scratch)) ?
64813498266Sopenharmony_ci              sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);
64913498266Sopenharmony_ci
65013498266Sopenharmony_ci            size_t actuallyread;
65113498266Sopenharmony_ci            Curl_set_in_callback(data, true);
65213498266Sopenharmony_ci            actuallyread = data->state.fread_func(scratch, 1,
65313498266Sopenharmony_ci                                                  readthisamountnow,
65413498266Sopenharmony_ci                                                  data->state.in);
65513498266Sopenharmony_ci            Curl_set_in_callback(data, false);
65613498266Sopenharmony_ci
65713498266Sopenharmony_ci            passed += actuallyread;
65813498266Sopenharmony_ci            if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
65913498266Sopenharmony_ci              /* this checks for greater-than only to make sure that the
66013498266Sopenharmony_ci                 CURL_READFUNC_ABORT return code still aborts */
66113498266Sopenharmony_ci              failf(data, "Failed to read data");
66213498266Sopenharmony_ci              return CURLE_FTP_COULDNT_USE_REST;
66313498266Sopenharmony_ci            }
66413498266Sopenharmony_ci          } while(passed < data->state.resume_from);
66513498266Sopenharmony_ci        }
66613498266Sopenharmony_ci
66713498266Sopenharmony_ci        /* now, decrease the size of the read */
66813498266Sopenharmony_ci        if(data->state.infilesize > 0) {
66913498266Sopenharmony_ci          data->state.infilesize -= data->state.resume_from;
67013498266Sopenharmony_ci          data->req.size = data->state.infilesize;
67113498266Sopenharmony_ci          Curl_pgrsSetUploadSize(data, data->state.infilesize);
67213498266Sopenharmony_ci        }
67313498266Sopenharmony_ci
67413498266Sopenharmony_ci        sshc->offset += data->state.resume_from;
67513498266Sopenharmony_ci      }
67613498266Sopenharmony_ci      if(data->state.infilesize > 0) {
67713498266Sopenharmony_ci        data->req.size = data->state.infilesize;
67813498266Sopenharmony_ci        Curl_pgrsSetUploadSize(data, data->state.infilesize);
67913498266Sopenharmony_ci      }
68013498266Sopenharmony_ci      /* upload data */
68113498266Sopenharmony_ci      Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
68213498266Sopenharmony_ci
68313498266Sopenharmony_ci      /* not set by Curl_setup_transfer to preserve keepon bits */
68413498266Sopenharmony_ci      conn->sockfd = conn->writesockfd;
68513498266Sopenharmony_ci
68613498266Sopenharmony_ci      if(result) {
68713498266Sopenharmony_ci        state(data, SSH_SFTP_CLOSE);
68813498266Sopenharmony_ci        sshc->actualcode = result;
68913498266Sopenharmony_ci      }
69013498266Sopenharmony_ci      else {
69113498266Sopenharmony_ci        /* store this original bitmask setup to use later on if we can't
69213498266Sopenharmony_ci           figure out a "real" bitmask */
69313498266Sopenharmony_ci        sshc->orig_waitfor = data->req.keepon;
69413498266Sopenharmony_ci
69513498266Sopenharmony_ci        /* we want to use the _sending_ function even when the socket turns
69613498266Sopenharmony_ci           out readable as the underlying libssh2 sftp send function will deal
69713498266Sopenharmony_ci           with both accordingly */
69813498266Sopenharmony_ci        data->state.select_bits = CURL_CSELECT_OUT;
69913498266Sopenharmony_ci
70013498266Sopenharmony_ci        /* since we don't really wait for anything at this point, we want the
70113498266Sopenharmony_ci           state machine to move on as soon as possible so we set a very short
70213498266Sopenharmony_ci           timeout here */
70313498266Sopenharmony_ci        Curl_expire(data, 0, EXPIRE_RUN_NOW);
70413498266Sopenharmony_ci
70513498266Sopenharmony_ci        state(data, SSH_STOP);
70613498266Sopenharmony_ci      }
70713498266Sopenharmony_ci      break;
70813498266Sopenharmony_ci    }
70913498266Sopenharmony_ci    case SSH_SFTP_DOWNLOAD_INIT:
71013498266Sopenharmony_ci      sshc->handleSz = sizeof(sshc->handle);
71113498266Sopenharmony_ci      rc = wolfSSH_SFTP_Open(sshc->ssh_session, sftp_scp->path,
71213498266Sopenharmony_ci                             WOLFSSH_FXF_READ, NULL,
71313498266Sopenharmony_ci                             sshc->handle, &sshc->handleSz);
71413498266Sopenharmony_ci      if(rc == WS_FATAL_ERROR)
71513498266Sopenharmony_ci        rc = wolfSSH_get_error(sshc->ssh_session);
71613498266Sopenharmony_ci      if(rc == WS_WANT_READ) {
71713498266Sopenharmony_ci        *block = TRUE;
71813498266Sopenharmony_ci        conn->waitfor = KEEP_RECV;
71913498266Sopenharmony_ci        return CURLE_OK;
72013498266Sopenharmony_ci      }
72113498266Sopenharmony_ci      else if(rc == WS_WANT_WRITE) {
72213498266Sopenharmony_ci        *block = TRUE;
72313498266Sopenharmony_ci        conn->waitfor = KEEP_SEND;
72413498266Sopenharmony_ci        return CURLE_OK;
72513498266Sopenharmony_ci      }
72613498266Sopenharmony_ci      else if(rc == WS_SUCCESS) {
72713498266Sopenharmony_ci        infof(data, "wolfssh SFTP open succeeded");
72813498266Sopenharmony_ci        state(data, SSH_SFTP_DOWNLOAD_STAT);
72913498266Sopenharmony_ci        return CURLE_OK;
73013498266Sopenharmony_ci      }
73113498266Sopenharmony_ci
73213498266Sopenharmony_ci      failf(data, "wolfssh SFTP open failed: %d", rc);
73313498266Sopenharmony_ci      return CURLE_SSH;
73413498266Sopenharmony_ci
73513498266Sopenharmony_ci    case SSH_SFTP_DOWNLOAD_STAT: {
73613498266Sopenharmony_ci      WS_SFTP_FILEATRB attrs;
73713498266Sopenharmony_ci      curl_off_t size;
73813498266Sopenharmony_ci
73913498266Sopenharmony_ci      rc = wolfSSH_SFTP_STAT(sshc->ssh_session, sftp_scp->path, &attrs);
74013498266Sopenharmony_ci      if(rc == WS_FATAL_ERROR)
74113498266Sopenharmony_ci        rc = wolfSSH_get_error(sshc->ssh_session);
74213498266Sopenharmony_ci      if(rc == WS_WANT_READ) {
74313498266Sopenharmony_ci        *block = TRUE;
74413498266Sopenharmony_ci        conn->waitfor = KEEP_RECV;
74513498266Sopenharmony_ci        return CURLE_OK;
74613498266Sopenharmony_ci      }
74713498266Sopenharmony_ci      else if(rc == WS_WANT_WRITE) {
74813498266Sopenharmony_ci        *block = TRUE;
74913498266Sopenharmony_ci        conn->waitfor = KEEP_SEND;
75013498266Sopenharmony_ci        return CURLE_OK;
75113498266Sopenharmony_ci      }
75213498266Sopenharmony_ci      else if(rc == WS_SUCCESS) {
75313498266Sopenharmony_ci        infof(data, "wolfssh STAT succeeded");
75413498266Sopenharmony_ci      }
75513498266Sopenharmony_ci      else {
75613498266Sopenharmony_ci        failf(data, "wolfssh SFTP open failed: %d", rc);
75713498266Sopenharmony_ci        data->req.size = -1;
75813498266Sopenharmony_ci        data->req.maxdownload = -1;
75913498266Sopenharmony_ci        Curl_pgrsSetDownloadSize(data, -1);
76013498266Sopenharmony_ci        return CURLE_SSH;
76113498266Sopenharmony_ci      }
76213498266Sopenharmony_ci
76313498266Sopenharmony_ci      size = ((curl_off_t)attrs.sz[1] <<32) | attrs.sz[0];
76413498266Sopenharmony_ci
76513498266Sopenharmony_ci      data->req.size = size;
76613498266Sopenharmony_ci      data->req.maxdownload = size;
76713498266Sopenharmony_ci      Curl_pgrsSetDownloadSize(data, size);
76813498266Sopenharmony_ci
76913498266Sopenharmony_ci      infof(data, "SFTP download %" CURL_FORMAT_CURL_OFF_T " bytes", size);
77013498266Sopenharmony_ci
77113498266Sopenharmony_ci      /* We cannot seek with wolfSSH so resuming and range requests are not
77213498266Sopenharmony_ci         possible */
77313498266Sopenharmony_ci      if(data->state.use_range || data->state.resume_from) {
77413498266Sopenharmony_ci        infof(data, "wolfSSH cannot do range/seek on SFTP");
77513498266Sopenharmony_ci        return CURLE_BAD_DOWNLOAD_RESUME;
77613498266Sopenharmony_ci      }
77713498266Sopenharmony_ci
77813498266Sopenharmony_ci      /* Setup the actual download */
77913498266Sopenharmony_ci      if(data->req.size == 0) {
78013498266Sopenharmony_ci        /* no data to transfer */
78113498266Sopenharmony_ci        Curl_setup_transfer(data, -1, -1, FALSE, -1);
78213498266Sopenharmony_ci        infof(data, "File already completely downloaded");
78313498266Sopenharmony_ci        state(data, SSH_STOP);
78413498266Sopenharmony_ci        break;
78513498266Sopenharmony_ci      }
78613498266Sopenharmony_ci      Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
78713498266Sopenharmony_ci
78813498266Sopenharmony_ci      /* not set by Curl_setup_transfer to preserve keepon bits */
78913498266Sopenharmony_ci      conn->writesockfd = conn->sockfd;
79013498266Sopenharmony_ci
79113498266Sopenharmony_ci      /* we want to use the _receiving_ function even when the socket turns
79213498266Sopenharmony_ci         out writableable as the underlying libssh2 recv function will deal
79313498266Sopenharmony_ci         with both accordingly */
79413498266Sopenharmony_ci      data->state.select_bits = CURL_CSELECT_IN;
79513498266Sopenharmony_ci
79613498266Sopenharmony_ci      if(result) {
79713498266Sopenharmony_ci        /* this should never occur; the close state should be entered
79813498266Sopenharmony_ci           at the time the error occurs */
79913498266Sopenharmony_ci        state(data, SSH_SFTP_CLOSE);
80013498266Sopenharmony_ci        sshc->actualcode = result;
80113498266Sopenharmony_ci      }
80213498266Sopenharmony_ci      else {
80313498266Sopenharmony_ci        state(data, SSH_STOP);
80413498266Sopenharmony_ci      }
80513498266Sopenharmony_ci      break;
80613498266Sopenharmony_ci    }
80713498266Sopenharmony_ci    case SSH_SFTP_CLOSE:
80813498266Sopenharmony_ci      if(sshc->handleSz)
80913498266Sopenharmony_ci        rc = wolfSSH_SFTP_Close(sshc->ssh_session, sshc->handle,
81013498266Sopenharmony_ci                                sshc->handleSz);
81113498266Sopenharmony_ci      else
81213498266Sopenharmony_ci        rc = WS_SUCCESS; /* directory listing */
81313498266Sopenharmony_ci      if(rc == WS_WANT_READ) {
81413498266Sopenharmony_ci        *block = TRUE;
81513498266Sopenharmony_ci        conn->waitfor = KEEP_RECV;
81613498266Sopenharmony_ci        return CURLE_OK;
81713498266Sopenharmony_ci      }
81813498266Sopenharmony_ci      else if(rc == WS_WANT_WRITE) {
81913498266Sopenharmony_ci        *block = TRUE;
82013498266Sopenharmony_ci        conn->waitfor = KEEP_SEND;
82113498266Sopenharmony_ci        return CURLE_OK;
82213498266Sopenharmony_ci      }
82313498266Sopenharmony_ci      else if(rc == WS_SUCCESS) {
82413498266Sopenharmony_ci        state(data, SSH_STOP);
82513498266Sopenharmony_ci        return CURLE_OK;
82613498266Sopenharmony_ci      }
82713498266Sopenharmony_ci
82813498266Sopenharmony_ci      failf(data, "wolfssh SFTP CLOSE failed: %d", rc);
82913498266Sopenharmony_ci      return CURLE_SSH;
83013498266Sopenharmony_ci
83113498266Sopenharmony_ci    case SSH_SFTP_READDIR_INIT:
83213498266Sopenharmony_ci      Curl_pgrsSetDownloadSize(data, -1);
83313498266Sopenharmony_ci      if(data->req.no_body) {
83413498266Sopenharmony_ci        state(data, SSH_STOP);
83513498266Sopenharmony_ci        break;
83613498266Sopenharmony_ci      }
83713498266Sopenharmony_ci      state(data, SSH_SFTP_READDIR);
83813498266Sopenharmony_ci      break;
83913498266Sopenharmony_ci
84013498266Sopenharmony_ci    case SSH_SFTP_READDIR:
84113498266Sopenharmony_ci      name = wolfSSH_SFTP_LS(sshc->ssh_session, sftp_scp->path);
84213498266Sopenharmony_ci      if(!name)
84313498266Sopenharmony_ci        rc = wolfSSH_get_error(sshc->ssh_session);
84413498266Sopenharmony_ci      else
84513498266Sopenharmony_ci        rc = WS_SUCCESS;
84613498266Sopenharmony_ci
84713498266Sopenharmony_ci      if(rc == WS_WANT_READ) {
84813498266Sopenharmony_ci        *block = TRUE;
84913498266Sopenharmony_ci        conn->waitfor = KEEP_RECV;
85013498266Sopenharmony_ci        return CURLE_OK;
85113498266Sopenharmony_ci      }
85213498266Sopenharmony_ci      else if(rc == WS_WANT_WRITE) {
85313498266Sopenharmony_ci        *block = TRUE;
85413498266Sopenharmony_ci        conn->waitfor = KEEP_SEND;
85513498266Sopenharmony_ci        return CURLE_OK;
85613498266Sopenharmony_ci      }
85713498266Sopenharmony_ci      else if(name && (rc == WS_SUCCESS)) {
85813498266Sopenharmony_ci        WS_SFTPNAME *origname = name;
85913498266Sopenharmony_ci        result = CURLE_OK;
86013498266Sopenharmony_ci        while(name) {
86113498266Sopenharmony_ci          char *line = aprintf("%s\n",
86213498266Sopenharmony_ci                               data->set.list_only ?
86313498266Sopenharmony_ci                               name->fName : name->lName);
86413498266Sopenharmony_ci          if(!line) {
86513498266Sopenharmony_ci            state(data, SSH_SFTP_CLOSE);
86613498266Sopenharmony_ci            sshc->actualcode = CURLE_OUT_OF_MEMORY;
86713498266Sopenharmony_ci            break;
86813498266Sopenharmony_ci          }
86913498266Sopenharmony_ci          result = Curl_client_write(data, CLIENTWRITE_BODY,
87013498266Sopenharmony_ci                                     line, strlen(line));
87113498266Sopenharmony_ci          free(line);
87213498266Sopenharmony_ci          if(result) {
87313498266Sopenharmony_ci            sshc->actualcode = result;
87413498266Sopenharmony_ci            break;
87513498266Sopenharmony_ci          }
87613498266Sopenharmony_ci          name = name->next;
87713498266Sopenharmony_ci        }
87813498266Sopenharmony_ci        wolfSSH_SFTPNAME_list_free(origname);
87913498266Sopenharmony_ci        state(data, SSH_STOP);
88013498266Sopenharmony_ci        return result;
88113498266Sopenharmony_ci      }
88213498266Sopenharmony_ci      failf(data, "wolfssh SFTP ls failed: %d", rc);
88313498266Sopenharmony_ci      return CURLE_SSH;
88413498266Sopenharmony_ci
88513498266Sopenharmony_ci    case SSH_SFTP_SHUTDOWN:
88613498266Sopenharmony_ci      Curl_safefree(sshc->homedir);
88713498266Sopenharmony_ci      wolfSSH_free(sshc->ssh_session);
88813498266Sopenharmony_ci      wolfSSH_CTX_free(sshc->ctx);
88913498266Sopenharmony_ci      state(data, SSH_STOP);
89013498266Sopenharmony_ci      return CURLE_OK;
89113498266Sopenharmony_ci    default:
89213498266Sopenharmony_ci      break;
89313498266Sopenharmony_ci    }
89413498266Sopenharmony_ci  } while(!rc && (sshc->state != SSH_STOP));
89513498266Sopenharmony_ci  return result;
89613498266Sopenharmony_ci}
89713498266Sopenharmony_ci
89813498266Sopenharmony_ci/* called repeatedly until done from multi.c */
89913498266Sopenharmony_cistatic CURLcode wssh_multi_statemach(struct Curl_easy *data, bool *done)
90013498266Sopenharmony_ci{
90113498266Sopenharmony_ci  struct connectdata *conn = data->conn;
90213498266Sopenharmony_ci  struct ssh_conn *sshc = &conn->proto.sshc;
90313498266Sopenharmony_ci  CURLcode result = CURLE_OK;
90413498266Sopenharmony_ci  bool block; /* we store the status and use that to provide a ssh_getsock()
90513498266Sopenharmony_ci                 implementation */
90613498266Sopenharmony_ci  do {
90713498266Sopenharmony_ci    result = wssh_statemach_act(data, &block);
90813498266Sopenharmony_ci    *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
90913498266Sopenharmony_ci    /* if there's no error, it isn't done and it didn't EWOULDBLOCK, then
91013498266Sopenharmony_ci       try again */
91113498266Sopenharmony_ci    if(*done) {
91213498266Sopenharmony_ci      DEBUGF(infof(data, "wssh_statemach_act says DONE"));
91313498266Sopenharmony_ci    }
91413498266Sopenharmony_ci  } while(!result && !*done && !block);
91513498266Sopenharmony_ci
91613498266Sopenharmony_ci  return result;
91713498266Sopenharmony_ci}
91813498266Sopenharmony_ci
91913498266Sopenharmony_cistatic
92013498266Sopenharmony_ciCURLcode wscp_perform(struct Curl_easy *data,
92113498266Sopenharmony_ci                      bool *connected,
92213498266Sopenharmony_ci                      bool *dophase_done)
92313498266Sopenharmony_ci{
92413498266Sopenharmony_ci  (void)data;
92513498266Sopenharmony_ci  (void)connected;
92613498266Sopenharmony_ci  (void)dophase_done;
92713498266Sopenharmony_ci  return CURLE_OK;
92813498266Sopenharmony_ci}
92913498266Sopenharmony_ci
93013498266Sopenharmony_cistatic
93113498266Sopenharmony_ciCURLcode wsftp_perform(struct Curl_easy *data,
93213498266Sopenharmony_ci                       bool *connected,
93313498266Sopenharmony_ci                       bool *dophase_done)
93413498266Sopenharmony_ci{
93513498266Sopenharmony_ci  CURLcode result = CURLE_OK;
93613498266Sopenharmony_ci
93713498266Sopenharmony_ci  DEBUGF(infof(data, "DO phase starts"));
93813498266Sopenharmony_ci
93913498266Sopenharmony_ci  *dophase_done = FALSE; /* not done yet */
94013498266Sopenharmony_ci
94113498266Sopenharmony_ci  /* start the first command in the DO phase */
94213498266Sopenharmony_ci  state(data, SSH_SFTP_QUOTE_INIT);
94313498266Sopenharmony_ci
94413498266Sopenharmony_ci  /* run the state-machine */
94513498266Sopenharmony_ci  result = wssh_multi_statemach(data, dophase_done);
94613498266Sopenharmony_ci
94713498266Sopenharmony_ci  *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
94813498266Sopenharmony_ci
94913498266Sopenharmony_ci  if(*dophase_done) {
95013498266Sopenharmony_ci    DEBUGF(infof(data, "DO phase is complete"));
95113498266Sopenharmony_ci  }
95213498266Sopenharmony_ci
95313498266Sopenharmony_ci  return result;
95413498266Sopenharmony_ci}
95513498266Sopenharmony_ci
95613498266Sopenharmony_ci/*
95713498266Sopenharmony_ci * The DO function is generic for both protocols.
95813498266Sopenharmony_ci */
95913498266Sopenharmony_cistatic CURLcode wssh_do(struct Curl_easy *data, bool *done)
96013498266Sopenharmony_ci{
96113498266Sopenharmony_ci  CURLcode result;
96213498266Sopenharmony_ci  bool connected = 0;
96313498266Sopenharmony_ci  struct connectdata *conn = data->conn;
96413498266Sopenharmony_ci  struct ssh_conn *sshc = &conn->proto.sshc;
96513498266Sopenharmony_ci
96613498266Sopenharmony_ci  *done = FALSE; /* default to false */
96713498266Sopenharmony_ci  data->req.size = -1; /* make sure this is unknown at this point */
96813498266Sopenharmony_ci  sshc->actualcode = CURLE_OK; /* reset error code */
96913498266Sopenharmony_ci  sshc->secondCreateDirs = 0;   /* reset the create dir attempt state
97013498266Sopenharmony_ci                                   variable */
97113498266Sopenharmony_ci
97213498266Sopenharmony_ci  Curl_pgrsSetUploadCounter(data, 0);
97313498266Sopenharmony_ci  Curl_pgrsSetDownloadCounter(data, 0);
97413498266Sopenharmony_ci  Curl_pgrsSetUploadSize(data, -1);
97513498266Sopenharmony_ci  Curl_pgrsSetDownloadSize(data, -1);
97613498266Sopenharmony_ci
97713498266Sopenharmony_ci  if(conn->handler->protocol & CURLPROTO_SCP)
97813498266Sopenharmony_ci    result = wscp_perform(data, &connected,  done);
97913498266Sopenharmony_ci  else
98013498266Sopenharmony_ci    result = wsftp_perform(data, &connected,  done);
98113498266Sopenharmony_ci
98213498266Sopenharmony_ci  return result;
98313498266Sopenharmony_ci}
98413498266Sopenharmony_ci
98513498266Sopenharmony_cistatic CURLcode wssh_block_statemach(struct Curl_easy *data,
98613498266Sopenharmony_ci                                    bool disconnect)
98713498266Sopenharmony_ci{
98813498266Sopenharmony_ci  struct connectdata *conn = data->conn;
98913498266Sopenharmony_ci  struct ssh_conn *sshc = &conn->proto.sshc;
99013498266Sopenharmony_ci  CURLcode result = CURLE_OK;
99113498266Sopenharmony_ci
99213498266Sopenharmony_ci  while((sshc->state != SSH_STOP) && !result) {
99313498266Sopenharmony_ci    bool block;
99413498266Sopenharmony_ci    timediff_t left = 1000;
99513498266Sopenharmony_ci    struct curltime now = Curl_now();
99613498266Sopenharmony_ci
99713498266Sopenharmony_ci    result = wssh_statemach_act(data, &block);
99813498266Sopenharmony_ci    if(result)
99913498266Sopenharmony_ci      break;
100013498266Sopenharmony_ci
100113498266Sopenharmony_ci    if(!disconnect) {
100213498266Sopenharmony_ci      if(Curl_pgrsUpdate(data))
100313498266Sopenharmony_ci        return CURLE_ABORTED_BY_CALLBACK;
100413498266Sopenharmony_ci
100513498266Sopenharmony_ci      result = Curl_speedcheck(data, now);
100613498266Sopenharmony_ci      if(result)
100713498266Sopenharmony_ci        break;
100813498266Sopenharmony_ci
100913498266Sopenharmony_ci      left = Curl_timeleft(data, NULL, FALSE);
101013498266Sopenharmony_ci      if(left < 0) {
101113498266Sopenharmony_ci        failf(data, "Operation timed out");
101213498266Sopenharmony_ci        return CURLE_OPERATION_TIMEDOUT;
101313498266Sopenharmony_ci      }
101413498266Sopenharmony_ci    }
101513498266Sopenharmony_ci
101613498266Sopenharmony_ci    if(!result) {
101713498266Sopenharmony_ci      int dir = conn->waitfor;
101813498266Sopenharmony_ci      curl_socket_t sock = conn->sock[FIRSTSOCKET];
101913498266Sopenharmony_ci      curl_socket_t fd_read = CURL_SOCKET_BAD;
102013498266Sopenharmony_ci      curl_socket_t fd_write = CURL_SOCKET_BAD;
102113498266Sopenharmony_ci      if(dir == KEEP_RECV)
102213498266Sopenharmony_ci        fd_read = sock;
102313498266Sopenharmony_ci      else if(dir == KEEP_SEND)
102413498266Sopenharmony_ci        fd_write = sock;
102513498266Sopenharmony_ci
102613498266Sopenharmony_ci      /* wait for the socket to become ready */
102713498266Sopenharmony_ci      (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write,
102813498266Sopenharmony_ci                              left>1000?1000:left); /* ignore result */
102913498266Sopenharmony_ci    }
103013498266Sopenharmony_ci  }
103113498266Sopenharmony_ci
103213498266Sopenharmony_ci  return result;
103313498266Sopenharmony_ci}
103413498266Sopenharmony_ci
103513498266Sopenharmony_ci/* generic done function for both SCP and SFTP called from their specific
103613498266Sopenharmony_ci   done functions */
103713498266Sopenharmony_cistatic CURLcode wssh_done(struct Curl_easy *data, CURLcode status)
103813498266Sopenharmony_ci{
103913498266Sopenharmony_ci  CURLcode result = CURLE_OK;
104013498266Sopenharmony_ci  struct SSHPROTO *sftp_scp = data->req.p.ssh;
104113498266Sopenharmony_ci
104213498266Sopenharmony_ci  if(!status) {
104313498266Sopenharmony_ci    /* run the state-machine */
104413498266Sopenharmony_ci    result = wssh_block_statemach(data, FALSE);
104513498266Sopenharmony_ci  }
104613498266Sopenharmony_ci  else
104713498266Sopenharmony_ci    result = status;
104813498266Sopenharmony_ci
104913498266Sopenharmony_ci  if(sftp_scp)
105013498266Sopenharmony_ci    Curl_safefree(sftp_scp->path);
105113498266Sopenharmony_ci  if(Curl_pgrsDone(data))
105213498266Sopenharmony_ci    return CURLE_ABORTED_BY_CALLBACK;
105313498266Sopenharmony_ci
105413498266Sopenharmony_ci  data->req.keepon = 0; /* clear all bits */
105513498266Sopenharmony_ci  return result;
105613498266Sopenharmony_ci}
105713498266Sopenharmony_ci
105813498266Sopenharmony_ci#if 0
105913498266Sopenharmony_cistatic CURLcode wscp_done(struct Curl_easy *data,
106013498266Sopenharmony_ci                         CURLcode code, bool premature)
106113498266Sopenharmony_ci{
106213498266Sopenharmony_ci  CURLcode result = CURLE_OK;
106313498266Sopenharmony_ci  (void)conn;
106413498266Sopenharmony_ci  (void)code;
106513498266Sopenharmony_ci  (void)premature;
106613498266Sopenharmony_ci
106713498266Sopenharmony_ci  return result;
106813498266Sopenharmony_ci}
106913498266Sopenharmony_ci
107013498266Sopenharmony_cistatic CURLcode wscp_doing(struct Curl_easy *data,
107113498266Sopenharmony_ci                          bool *dophase_done)
107213498266Sopenharmony_ci{
107313498266Sopenharmony_ci  CURLcode result = CURLE_OK;
107413498266Sopenharmony_ci  (void)conn;
107513498266Sopenharmony_ci  (void)dophase_done;
107613498266Sopenharmony_ci
107713498266Sopenharmony_ci  return result;
107813498266Sopenharmony_ci}
107913498266Sopenharmony_ci
108013498266Sopenharmony_cistatic CURLcode wscp_disconnect(struct Curl_easy *data,
108113498266Sopenharmony_ci                                struct connectdata *conn, bool dead_connection)
108213498266Sopenharmony_ci{
108313498266Sopenharmony_ci  CURLcode result = CURLE_OK;
108413498266Sopenharmony_ci  (void)data;
108513498266Sopenharmony_ci  (void)conn;
108613498266Sopenharmony_ci  (void)dead_connection;
108713498266Sopenharmony_ci
108813498266Sopenharmony_ci  return result;
108913498266Sopenharmony_ci}
109013498266Sopenharmony_ci#endif
109113498266Sopenharmony_ci
109213498266Sopenharmony_cistatic CURLcode wsftp_done(struct Curl_easy *data,
109313498266Sopenharmony_ci                          CURLcode code, bool premature)
109413498266Sopenharmony_ci{
109513498266Sopenharmony_ci  (void)premature;
109613498266Sopenharmony_ci  state(data, SSH_SFTP_CLOSE);
109713498266Sopenharmony_ci
109813498266Sopenharmony_ci  return wssh_done(data, code);
109913498266Sopenharmony_ci}
110013498266Sopenharmony_ci
110113498266Sopenharmony_cistatic CURLcode wsftp_doing(struct Curl_easy *data,
110213498266Sopenharmony_ci                           bool *dophase_done)
110313498266Sopenharmony_ci{
110413498266Sopenharmony_ci  CURLcode result = wssh_multi_statemach(data, dophase_done);
110513498266Sopenharmony_ci
110613498266Sopenharmony_ci  if(*dophase_done) {
110713498266Sopenharmony_ci    DEBUGF(infof(data, "DO phase is complete"));
110813498266Sopenharmony_ci  }
110913498266Sopenharmony_ci  return result;
111013498266Sopenharmony_ci}
111113498266Sopenharmony_ci
111213498266Sopenharmony_cistatic CURLcode wsftp_disconnect(struct Curl_easy *data,
111313498266Sopenharmony_ci                                 struct connectdata *conn,
111413498266Sopenharmony_ci                                 bool dead)
111513498266Sopenharmony_ci{
111613498266Sopenharmony_ci  CURLcode result = CURLE_OK;
111713498266Sopenharmony_ci  (void)dead;
111813498266Sopenharmony_ci
111913498266Sopenharmony_ci  DEBUGF(infof(data, "SSH DISCONNECT starts now"));
112013498266Sopenharmony_ci
112113498266Sopenharmony_ci  if(conn->proto.sshc.ssh_session) {
112213498266Sopenharmony_ci    /* only if there's a session still around to use! */
112313498266Sopenharmony_ci    state(data, SSH_SFTP_SHUTDOWN);
112413498266Sopenharmony_ci    result = wssh_block_statemach(data, TRUE);
112513498266Sopenharmony_ci  }
112613498266Sopenharmony_ci
112713498266Sopenharmony_ci  DEBUGF(infof(data, "SSH DISCONNECT is done"));
112813498266Sopenharmony_ci  return result;
112913498266Sopenharmony_ci}
113013498266Sopenharmony_ci
113113498266Sopenharmony_cistatic int wssh_getsock(struct Curl_easy *data,
113213498266Sopenharmony_ci                        struct connectdata *conn,
113313498266Sopenharmony_ci                        curl_socket_t *sock)
113413498266Sopenharmony_ci{
113513498266Sopenharmony_ci  int bitmap = GETSOCK_BLANK;
113613498266Sopenharmony_ci  int dir = conn->waitfor;
113713498266Sopenharmony_ci  (void)data;
113813498266Sopenharmony_ci  sock[0] = conn->sock[FIRSTSOCKET];
113913498266Sopenharmony_ci
114013498266Sopenharmony_ci  if(dir == KEEP_RECV)
114113498266Sopenharmony_ci    bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
114213498266Sopenharmony_ci  else if(dir == KEEP_SEND)
114313498266Sopenharmony_ci    bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
114413498266Sopenharmony_ci
114513498266Sopenharmony_ci  return bitmap;
114613498266Sopenharmony_ci}
114713498266Sopenharmony_ci
114813498266Sopenharmony_civoid Curl_ssh_version(char *buffer, size_t buflen)
114913498266Sopenharmony_ci{
115013498266Sopenharmony_ci  (void)msnprintf(buffer, buflen, "wolfssh/%s", LIBWOLFSSH_VERSION_STRING);
115113498266Sopenharmony_ci}
115213498266Sopenharmony_ci
115313498266Sopenharmony_ciCURLcode Curl_ssh_init(void)
115413498266Sopenharmony_ci{
115513498266Sopenharmony_ci  if(WS_SUCCESS != wolfSSH_Init()) {
115613498266Sopenharmony_ci    DEBUGF(fprintf(stderr, "Error: wolfSSH_Init failed\n"));
115713498266Sopenharmony_ci    return CURLE_FAILED_INIT;
115813498266Sopenharmony_ci  }
115913498266Sopenharmony_ci
116013498266Sopenharmony_ci  return CURLE_OK;
116113498266Sopenharmony_ci}
116213498266Sopenharmony_civoid Curl_ssh_cleanup(void)
116313498266Sopenharmony_ci{
116413498266Sopenharmony_ci  (void)wolfSSH_Cleanup();
116513498266Sopenharmony_ci}
116613498266Sopenharmony_ci
116713498266Sopenharmony_ci#endif /* USE_WOLFSSH */
1168