Skip to content
Snippets Groups Projects
ssh.c 67.9 KiB
Newer Older
  • Learn to ignore specific revisions
  •   } else {
        result = ssh_easy_statemach(conn);
        *dophase_done = TRUE; /* with the easy interface we are done here */
      }
      *connected = conn->bits.tcpconnect;
    
      if (*dophase_done) {
        DEBUGF(infof(conn->data, "DO phase is complete\n"));
      }
    
      return result;
    }
    
    /* called from multi.c while DOing */
    CURLcode Curl_sftp_doing(struct connectdata *conn,
                             bool *dophase_done)
    {
      CURLcode result;
      result = Curl_ssh_multi_statemach(conn, dophase_done);
    
      if (*dophase_done) {
        DEBUGF(infof(conn->data, "DO phase is complete\n"));
      }
      return result;
    }
    
    
    CURLcode Curl_sftp_do(struct connectdata *conn, bool *done)
    {
    
      CURLcode res;
      bool connected = 0;
      struct SessionHandle *data = conn->data;
    
      *done = FALSE; /* default to false */
    
      /*
       * Since connections can be re-used between SessionHandles, this might be a
       * connection already existing but on a fresh SessionHandle struct so we must
       * make sure we have a good 'struct SSHPROTO' to play with. For new
       * connections, the struct SSHPROTO is allocated and setup in the
       * Curl_ssh_connect() function.
       */
      res = ssh_init(conn);
      if (res) {
        return res;
      }
    
      data->reqdata.size = -1; /* make sure this is unknown at this point */
    
      Curl_pgrsSetUploadCounter(data, 0);
      Curl_pgrsSetDownloadCounter(data, 0);
      Curl_pgrsSetUploadSize(data, 0);
      Curl_pgrsSetDownloadSize(data, 0);
    
      res = sftp_perform(conn, &connected,  done);
    
      if (CURLE_OK == res) {
    
        if (!done) {
          /* the DO phase has not completed yet */
          return CURLE_OK;
        }
      }
    
      return res;
    
    CURLcode Curl_sftp_done(struct connectdata *conn, CURLcode status,
                            bool premature)
    
      CURLcode result = CURLE_OK;
      bool done = FALSE;
      struct ssh_conn *sshc = &conn->proto.sshc;
    
    
      if (status == CURLE_OK) {
        /* Before we shut down, see if there are any post-quote commands to send: */
        if (!status && !premature && conn->data->set.postquote) {
          sshc->nextState = SSH_SFTP_CLOSE;
          state(conn, SSH_SFTP_POSTQUOTE_INIT);
        } else {
          state(conn, SSH_SFTP_CLOSE);
        }
    
        /* run the state-machine */
        if (conn->data->state.used_interface == Curl_if_multi) {
          result = Curl_ssh_multi_statemach(conn, &done);
        } else {
          result = ssh_easy_statemach(conn);
          done = TRUE;
        }
      } else {
        result = status;
        done = TRUE;
      }
    
      if (done) {
        Curl_safefree(conn->data->reqdata.proto.ssh);
        conn->data->reqdata.proto.ssh = NULL;
        Curl_pgrsDone(conn);
      }
    
      return result;
    
    }
    
    /* return number of received (decrypted) bytes */
    ssize_t Curl_sftp_send(struct connectdata *conn, int sockindex,
                           void *mem, size_t len)
    {
    
      ssize_t nwrite;   /* libssh2_sftp_write() used to return size_t in 0.14
                           but is changed to ssize_t in 0.15! */
    
    
      nwrite = (ssize_t)
        libssh2_sftp_write(conn->data->reqdata.proto.ssh->sftp_handle, mem, len);
    
    /*
     * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
     * a regular CURLcode value.
     */
    ssize_t Curl_sftp_recv(struct connectdata *conn, int sockindex,
                           char *mem, size_t len)
    {
      ssize_t nread;
      (void)sockindex;
    
      /* libssh2_sftp_read() returns size_t !*/
      nread = (ssize_t)
        libssh2_sftp_read(conn->data->reqdata.proto.ssh->sftp_handle, mem, len);
    
    /* The get_pathname() function is being borrowed from OpenSSH sftp.c
       version 4.6p1. */
    /*
     * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
     *
     * Permission to use, copy, modify, and distribute this software for any
     * purpose with or without fee is hereby granted, provided that the above
     * copyright notice and this permission notice appear in all copies.
     *
     * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     */
    static int
    get_pathname(const char **cpp, char **path)
    {
      const char *cp = *cpp, *end;
      char quot;
      u_int i, j;
    
      static const char * const WHITESPACE = " \t\r\n";
    
    
      cp += strspn(cp, WHITESPACE);
      if (!*cp) {
        *cpp = cp;
        *path = NULL;
    
      }
    
      *path = malloc(strlen(cp) + 1);
      if (*path == NULL)
        return CURLE_OUT_OF_MEMORY;
    
      /* Check for quoted filenames */
      if (*cp == '\"' || *cp == '\'') {
        quot = *cp++;
    
        /* Search for terminating quote, unescape some chars */
        for (i = j = 0; i <= strlen(cp); i++) {
          if (cp[i] == quot) {  /* Found quote */
            i++;
            (*path)[j] = '\0';
            break;
          }
          if (cp[i] == '\0') {  /* End of string */
            /*error("Unterminated quote");*/
            goto fail;
          }
          if (cp[i] == '\\') {  /* Escaped characters */
            i++;
            if (cp[i] != '\'' && cp[i] != '\"' &&
                cp[i] != '\\') {
              /*error("Bad escaped character '\\%c'",
                  cp[i]);*/
              goto fail;
            }
          }
          (*path)[j++] = cp[i];
        }
    
        if (j == 0) {
          /*error("Empty quotes");*/
          goto fail;
        }
        *cpp = cp + i + strspn(cp + i, WHITESPACE);
      }
      else {
        /* Read to end of filename */
        end = strpbrk(cp, WHITESPACE);
        if (end == NULL)
          end = strchr(cp, '\0');
        *cpp = end + strspn(end, WHITESPACE);
    
        memcpy(*path, cp, end - cp);
        (*path)[end - cp] = '\0';
      }
      return (0);
    
      fail:
    
    }
    
    
    static const char *sftp_libssh2_strerror(unsigned long err)
    {
      switch (err) {
    
        case LIBSSH2_FX_NO_SUCH_FILE:
          return "No such file or directory";
    
        case LIBSSH2_FX_PERMISSION_DENIED:
          return "Permission denied";
    
        case LIBSSH2_FX_FAILURE:
          return "Operation failed";
    
        case LIBSSH2_FX_BAD_MESSAGE:
          return "Bad message from SFTP server";
    
        case LIBSSH2_FX_NO_CONNECTION:
          return "Not connected to SFTP server";
    
        case LIBSSH2_FX_CONNECTION_LOST:
          return "Connection to SFTP server lost";
    
        case LIBSSH2_FX_OP_UNSUPPORTED:
          return "Operation not supported by SFTP server";
    
        case LIBSSH2_FX_INVALID_HANDLE:
          return "Invalid handle";
    
        case LIBSSH2_FX_NO_SUCH_PATH:
          return "No such file or directory";
    
        case LIBSSH2_FX_FILE_ALREADY_EXISTS:
          return "File already exists";
    
        case LIBSSH2_FX_WRITE_PROTECT:
          return "File is write protected";
    
        case LIBSSH2_FX_NO_MEDIA:
          return "No media";
    
        case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM:
          return "Disk full";
    
        case LIBSSH2_FX_QUOTA_EXCEEDED:
          return "User quota exceeded";
    
        case LIBSSH2_FX_UNKNOWN_PRINCIPLE:
          return "Unknown principle";
    
        case LIBSSH2_FX_LOCK_CONFlICT:
          return "File lock conflict";
    
        case LIBSSH2_FX_DIR_NOT_EMPTY:
          return "Directory not empty";
    
        case LIBSSH2_FX_NOT_A_DIRECTORY:
          return "Not a directory";
    
        case LIBSSH2_FX_INVALID_FILENAME:
          return "Invalid filename";
    
        case LIBSSH2_FX_LINK_LOOP:
          return "Link points to itself";
    
    #endif /* USE_LIBSSH2 */