Skip to content
ssh.c 75 KiB
Newer Older

      /* the arguments following the command must be separated from the
         command with a space so we can check for it unconditionally */
      cp = strchr(item->data, ' ');
      if (cp == NULL) {
        failf(data, "Syntax error in SFTP command. Supply parameter(s)!");
        return CURLE_FTP_QUOTE_ERROR;
      }

      /* also, every command takes at least one argument so we get that first
         argument right now */
      err = get_pathname(&cp, &path1);
      if (err) {
        if (err == CURLE_OUT_OF_MEMORY)
          failf(data, "Out of memory");
        else
          failf(data, "Syntax error: Bad first parameter");
        return err;
      }

      /* SFTP is a binary protocol, so we don't send text commands to the
         server. Instead, we scan for commands for commands used by OpenSSH's
         sftp program and call the appropriate libssh2 functions. */
      if (curl_strnequal(item->data, "chgrp ", 6) ||
          curl_strnequal(item->data, "chmod ", 6) ||
          curl_strnequal(item->data, "chown ", 6) ) { /* attribute change */
        LIBSSH2_SFTP_ATTRIBUTES attrs;

        /* path1 contains the mode to set */
        err = get_pathname(&cp, &path2);  /* get the destination */
        if (err) {
          if (err == CURLE_OUT_OF_MEMORY)
            failf(data, "Out of memory");
          else
            failf(data,
                  "Syntax error in chgrp/chmod/chown: Bad second parameter");
          free(path1);
          return err;
        }
        memset(&attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
        if (libssh2_sftp_stat(sftp_session,
                              path2, &attrs) != 0) { /* get those attributes */
          err = libssh2_sftp_last_error(sftp_session);
          free(path1);
          free(path2);
          failf(data, "Attempt to get SFTP stats failed: %s",
                sftp_libssh2_strerror(err));
          return CURLE_FTP_QUOTE_ERROR;
        }
#if (LIBSSH2_APINO >= 200706012030)
        while ((ret = libssh2_sftp_stat(sftp_session,
                                        path2, &attrs)) ==
               LIBSSH2_ERROR_EAGAIN);
        if (ret != 0) { /* get those attributes */
          err = libssh2_sftp_last_error(sftp_session);
          free(path1);
          free(path2);
          failf(data, "Attempt to get SFTP stats failed: %s",
                sftp_libssh2_strerror(err));
          return CURLE_FTP_QUOTE_ERROR;
        }
#else /* !(LIBSSH2_APINO >= 200706012030) */
        if (libssh2_sftp_stat(sftp_session,
                              path2, &attrs) != 0) { /* get those attributes */
          err = libssh2_sftp_last_error(sftp_session);
          free(path1);
          free(path2);
          failf(data, "Attempt to get SFTP stats failed: %s",
                sftp_libssh2_strerror(err));
          return CURLE_FTP_QUOTE_ERROR;
        }
#endif /* !(LIBSSH2_APINO >= 200706012030) */

        /* Now set the new attributes... */
        if (curl_strnequal(item->data, "chgrp", 5)) {
          attrs.gid = strtol(path1, NULL, 10);
          if (attrs.gid == 0 && !ISDIGIT(path1[0])) {
            free(path1);
            free(path2);
            failf(data, "Syntax error: chgrp gid not a number");
            return CURLE_FTP_QUOTE_ERROR;
          }
        }
        else if (curl_strnequal(item->data, "chmod", 5)) {
          attrs.permissions = strtol(path1, NULL, 8);/* permissions are octal */
          if (attrs.permissions == 0 && !ISDIGIT(path1[0])) {
            free(path1);
            free(path2);
            failf(data, "Syntax error: chmod permissions not a number");
            return CURLE_FTP_QUOTE_ERROR;
          }
        }
        else if (curl_strnequal(item->data, "chown", 5)) {
          attrs.uid = strtol(path1, NULL, 10);
          if (attrs.uid == 0 && !ISDIGIT(path1[0])) {
            free(path1);
            free(path2);
            failf(data, "Syntax error: chown uid not a number");
            return CURLE_FTP_QUOTE_ERROR;
          }
        }

        /* Now send the completed structure... */
#if (LIBSSH2_APINO >= 200706012030)
        while ((ret = libssh2_sftp_setstat(sftp_session, path2, &attrs)) ==
               LIBSSH2_ERROR_EAGAIN);
        if (ret != 0) {
          err = libssh2_sftp_last_error(sftp_session);
          free(path1);
          free(path2);
          failf(data, "Attempt to set SFTP stats failed: %s",
                sftp_libssh2_strerror(err));
          return CURLE_FTP_QUOTE_ERROR;
        }
#else /* !(LIBSSH2_APINO >= 200706012030) */
        if (libssh2_sftp_setstat(sftp_session, path2, &attrs) != 0) {
          err = libssh2_sftp_last_error(sftp_session);
          free(path1);
          free(path2);
          failf(data, "Attempt to set SFTP stats failed: %s",
                sftp_libssh2_strerror(err));
          return CURLE_FTP_QUOTE_ERROR;
        }
#endif /* !(LIBSSH2_APINO >= 200706012030) */
      }
      else if (curl_strnequal(item->data, "ln ", 3) ||
               curl_strnequal(item->data, "symlink ", 8)) {
        /* symbolic linking */
        /* path1 is the source */
        err = get_pathname(&cp, &path2);  /* get the destination */
        if (err) {
          if (err == CURLE_OUT_OF_MEMORY)
            failf(data, "Out of memory");
          else
            failf(data,
                  "Syntax error in ln/symlink: Bad second parameter");
          free(path1);
          return err;
        }
#if (LIBSSH2_APINO >= 200706012030)
        while ((ret = libssh2_sftp_symlink(sftp_session, path1, path2)) ==
               LIBSSH2_ERROR_EAGAIN);
        if (ret != 0) {
          err = libssh2_sftp_last_error(sftp_session);
          free(path1);
          free(path2);
          failf(data, "symlink command failed: %s",
                sftp_libssh2_strerror(err));
          return CURLE_FTP_QUOTE_ERROR;
        }
#else /* !(LIBSSH2_APINO >= 200706012030) */
        if (libssh2_sftp_symlink(sftp_session, path1, path2) != 0) {
          err = libssh2_sftp_last_error(sftp_session);
          free(path1);
          free(path2);
          failf(data, "symlink command failed: %s",
                sftp_libssh2_strerror(err));
          return CURLE_FTP_QUOTE_ERROR;
        }
#endif /* !(LIBSSH2_APINO >= 200706012030) */
      }
      else if (curl_strnequal(item->data, "mkdir ", 6)) { /* create dir */
#if (LIBSSH2_APINO >= 200706012030)
        while ((ret = libssh2_sftp_mkdir(sftp_session, path1, 0744)) ==
               LIBSSH2_ERROR_EAGAIN);
        if (ret != 0) {
          err = libssh2_sftp_last_error(sftp_session);
          free(path1);
          failf(data, "mkdir command failed: %s", sftp_libssh2_strerror(err));
          return CURLE_FTP_QUOTE_ERROR;
        }
#else /* !(LIBSSH2_APINO >= 200706012030) */
        if (libssh2_sftp_mkdir(sftp_session, path1, 0744) != 0) {
          err = libssh2_sftp_last_error(sftp_session);
          free(path1);
          failf(data, "mkdir command failed: %s",
                sftp_libssh2_strerror(err));
          return CURLE_FTP_QUOTE_ERROR;
        }
#endif /* !(LIBSSH2_APINO >= 200706012030) */
      }
      else if (curl_strnequal(item->data, "rename ", 7)) { /* rename file */
        /* first param is the source path */
        err = get_pathname(&cp, &path2);  /* second param is the dest. path */
        if (err) {
          if (err == CURLE_OUT_OF_MEMORY)
            failf(data, "Out of memory");
          else
            failf(data,
                  "Syntax error in rename: Bad second parameter");
          free(path1);
          return err;
        }
#if (LIBSSH2_APINO >= 200706012030)
        while ((ret = libssh2_sftp_rename(sftp_session, path1, path2)) ==
               LIBSSH2_ERROR_EAGAIN);
        if (ret != 0) {
          err = libssh2_sftp_last_error(sftp_session);
          free(path1);
          free(path2);
          failf(data, "rename command failed: %s", sftp_libssh2_strerror(err));
          return CURLE_FTP_QUOTE_ERROR;
        }
#else /* !(LIBSSH2_APINO >= 200706012030) */
        if (libssh2_sftp_rename(sftp_session,
                                path1, path2) != 0) {
          err = libssh2_sftp_last_error(sftp_session);
          free(path1);
          free(path2);
          failf(data, "rename command failed: %s",
                sftp_libssh2_strerror(err));
          return CURLE_FTP_QUOTE_ERROR;
        }
#endif /* !(LIBSSH2_APINO >= 200706012030) */
      }
      else if (curl_strnequal(item->data, "rmdir ", 6)) { /* delete dir */
#if (LIBSSH2_APINO >= 200706012030)
        while ((ret = libssh2_sftp_rmdir(sftp_session, path1)) ==
               LIBSSH2_ERROR_EAGAIN);
        if (ret != 0) {
          err = libssh2_sftp_last_error(sftp_session);
          free(path1);
          failf(data, "rmdir command failed: %s", sftp_libssh2_strerror(err));
          return CURLE_FTP_QUOTE_ERROR;
        }
#else /* !(LIBSSH2_APINO >= 200706012030) */
        if (libssh2_sftp_rmdir(sftp_session,
                               path1) != 0) {
          err = libssh2_sftp_last_error(sftp_session);
          free(path1);
          failf(data, "rmdir command failed: %s",
                sftp_libssh2_strerror(err));
          return CURLE_FTP_QUOTE_ERROR;
        }
#endif /* !(LIBSSH2_APINO >= 200706012030) */
      }
      else if (curl_strnequal(item->data, "rm ", 3)) { /* delete file */
#if (LIBSSH2_APINO >= 200706012030)
        while ((ret = libssh2_sftp_unlink(sftp_session, path1)) ==
               LIBSSH2_ERROR_EAGAIN);
        if (ret != 0) {
          err = libssh2_sftp_last_error(sftp_session);
          free(path1);
          failf(data, "rm command failed: %s", sftp_libssh2_strerror(err));
          return CURLE_FTP_QUOTE_ERROR;
        }
#else /* !(LIBSSH2_APINO >= 200706012030) */
        if (libssh2_sftp_unlink(sftp_session, path1) != 0) {
          err = libssh2_sftp_last_error(sftp_session);
          free(path1);
          failf(data, "rm command failed: %s",
                sftp_libssh2_strerror(err));
          return CURLE_FTP_QUOTE_ERROR;
        }
#endif /* !(LIBSSH2_APINO >= 200706012030) */
      }

      if (path1)
        free(path1);
      if (path2)
        free(path2);
    }
    item = item->next;
  }
  (void)ret;    /* possibly unused */

 * Create the path sftp->path on the remote site
 * returns CURL_OK on success, -1 on failure
static CURLcode sftp_create_dirs(struct connectdata *conn) {
  CURLcode result = CURLE_OK;
  unsigned int sftp_err = 0;
  int rc;
  struct SSHPROTO *sftp = conn->data->reqdata.proto.ssh;
  if (strlen(sftp->path) > 1) {
    char *slash_pos = sftp->path + 1; /* ignore the leading '/' */
    while ((slash_pos = strchr(slash_pos, '/')) != NULL) {
      *slash_pos = 0;
      infof(conn->data, "Creating directory '%s'\n", sftp->path);
      /* 'mode' - parameter is preliminary - default to 0644 */
#if (LIBSSH2_APINO >= 200706012030)
      while ((rc = libssh2_sftp_mkdir(sftp->sftp_session, sftp->path,
                               LIBSSH2_SFTP_S_IRWXU |
                               LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IXGRP |
                               LIBSSH2_SFTP_S_IROTH | LIBSSH2_SFTP_S_IXOTH)) ==
             LIBSSH2_ERROR_EAGAIN);
#else /* !(LIBSSH2_APINO >= 200706012030) */
      rc = libssh2_sftp_mkdir(sftp->sftp_session, sftp->path,
                               LIBSSH2_SFTP_S_IRWXU |
                               LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IXGRP |
                               LIBSSH2_SFTP_S_IROTH | LIBSSH2_SFTP_S_IXOTH);
#endif /* !(LIBSSH2_APINO >= 200706012030) */
      *slash_pos = '/';
      ++slash_pos;
        /* abort if failure wasn't that the dir already exists or the
         * permission was denied (creation might succeed further
         * down the path) - retry on unspecific FAILURE also
         */
        sftp_err = libssh2_sftp_last_error(sftp->sftp_session);
        if ((sftp_err != LIBSSH2_FX_FILE_ALREADY_EXISTS) &&
            (sftp_err != LIBSSH2_FX_FAILURE) &&
            (sftp_err != LIBSSH2_FX_PERMISSION_DENIED)) {
          result = -1;
          break;
        }
      }
    }
  }
  return result;