From: Petr Tesarik <ptesarik@suse.cz>
Date: Tue, 14 Apr 2015 11:25:48 +0200
Subject: Dummy SFTPTransfer based on external ssh command
References: FATE#318874, bsc#917747
Patch-mainline: v0.8.16
Git-commit: 9e6fdc729f7b8f695775ef0afa0a591747483e4a 

This implementation will use standard input/output to control an ssh
subprocess.

This is a dummy implementation which only starts the subshell but
does nothing.

Signed-off-by: Petr Tesarik <ptesarik@suse.cz>

---
 kdumptool/sshtransfer.cc |  291 +++++------------------------------------------
 kdumptool/sshtransfer.h  |   26 ----
 kdumptool/transfer.cc    |    2 
 3 files changed, 36 insertions(+), 283 deletions(-)

--- a/kdumptool/transfer.cc
+++ b/kdumptool/transfer.cc
@@ -90,11 +90,9 @@ Transfer *URLTransfer::getTransfer(const
             Debug::debug()->dbg("Returning FTPTransfer");
             return new FTPTransfer(urlv, subdir);
 
-#if HAVE_LIBSSH2
         case URLParser::PROT_SFTP:
             Debug::debug()->dbg("Returning SFTPTransfer");
             return new SFTPTransfer(urlv, subdir);
-#endif // HAVE_LIBSSH2
 
         case URLParser::PROT_SSH:
 	    Debug::debug()->dbg("Returning SSHTransfer");
--- a/kdumptool/sshtransfer.cc
+++ b/kdumptool/sshtransfer.cc
@@ -21,11 +21,7 @@
 #include <cstdlib>
 #include <cerrno>
 #include <stdint.h>
-
-#if HAVE_LIBSSH2
-#   include <libssh2.h>
-#   include <libssh2_sftp.h>
-#endif
+#include <unistd.h>
 
 #include "global.h"
 #include "debug.h"
@@ -250,14 +246,11 @@ ByteVector const &SFTPPacket::update(voi
 //}}}
 //{{{ SFTPTransfer -------------------------------------------------------------
 
-#if HAVE_LIBSSH2
-
 /* -------------------------------------------------------------------------- */
 SFTPTransfer::SFTPTransfer(const RootDirURLVector &urlv,
 			   const std::string &subdir)
     throw (KError)
-    : URLTransfer(urlv, subdir),
-      m_sshSession(NULL), m_sftp(NULL), m_socket(NULL)
+    : URLTransfer(urlv, subdir)
 {
     if (urlv.size() > 1)
 	cerr << "WARNING: First dump target used; rest ignored." << endl;
@@ -266,141 +259,12 @@ SFTPTransfer::SFTPTransfer(const RootDir
     Debug::debug()->trace("SFTPTransfer::SFTPTransfer(%s)",
 			  parser.getURL().c_str());
 
-    m_sshSession = libssh2_session_init();
-    if (!m_sshSession)
-        throw KError("libssh2_session_init() failed.");
-
-    // set blocking
-    libssh2_session_set_blocking(m_sshSession, 1);
-
-    // get the correct port
-    int port = parser.getPort();
-    if (port <= 0)
-        port = Socket::DP_SSH;
-
-    // create the socket and connect
-    m_socket = new Socket(parser.getHostname(), port, Socket::ST_TCP);
-    int fd = m_socket->connect();
-
-    // start it up
-    int ret = libssh2_session_startup(m_sshSession, fd);
-    if (ret != 0) {
-        close();
-        throw KError("libssh2_session_startup() failed with "+
-            Stringutil::number2string(ret) +".");
-    }
-
-    // get the hostkey fingerprints
-    const char *hostsha1 =
-	libssh2_hostkey_hash(m_sshSession, LIBSSH2_HOSTKEY_HASH_SHA1);
-    Debug::debug()->info
-	("SSH SHA1 fingerprint: %s",
-	 Stringutil::bytes2hexstr(hostsha1, SHA1SUM_LENGTH, true).c_str());
-
-    const char *hostmd5 =
-	libssh2_hostkey_hash(m_sshSession, LIBSSH2_HOSTKEY_HASH_MD5);
-    Debug::debug()->info
-	("SSH MD5 fingerprint: %s",
-	 Stringutil::bytes2hexstr(hostmd5, MD5SUM_LENGTH, true).c_str());
-
-#if HAVE_LIBSSL
-    // check the fingerprints if possible
-    Configuration *config = Configuration::config();
-    const string &hostkey = config->KDUMP_HOST_KEY.value();
-
-    if (!hostkey.empty() && hostkey != "*") {
-	char expectmd5[MD5SUM_LENGTH];
-	char expectsha1[SHA1SUM_LENGTH];
-	Stringutil::digest_base64(hostkey.c_str(), hostkey.size(),
-				  expectmd5, expectsha1);
-
-	if (memcmp(hostsha1, expectsha1, SHA1SUM_LENGTH))
-	    throw KError("Target host key SHA1 fingerprint mismatch!");
-	Debug::debug()->info("SHA1 fingerprint matches");
-
-	if (memcmp(hostmd5, expectmd5, MD5SUM_LENGTH))
-	    throw KError("Target host key MD5 fingerprint mismatch!");
-	Debug::debug()->info("MD5 fingerprint matches");
-    } else
-	cerr << "WARNING: SSH host key accepted without checking!" << endl;
-#endif	// HAVE_LIBSSL
-
-    // SSH authentication
-    bool authenticated = false;
-
-    // username and password
-    string username = parser.getUsername();
-    string password = parser.getPassword();
-
-    // public and private key
-    string homedir = getenv("HOME");
-    FilePath pubkey;
-    FilePath privkey;
-
-    // DSA
-    (pubkey = homedir).appendPath(".ssh").appendPath("id_dsa.pub");
-    (privkey = homedir).appendPath(".ssh").appendPath("id_dsa");
-    if (!authenticated && pubkey.exists() && privkey.exists()) {
-        Debug::debug()->dbg("Using private key %s and public key %s",
-                privkey.c_str(), pubkey.c_str());
-
-        ret = libssh2_userauth_publickey_fromfile(m_sshSession,
-                username.c_str(), pubkey.c_str(), privkey.c_str(),
-                password.c_str());
-        if (ret == 0)
-            authenticated = true;
-        else
-            Debug::debug()->dbg("id_dsa: "
-                "libssh2_userauth_publickey_fromfile() failed with "+
-                Stringutil::number2string(ret) + ".");
-    }
+    m_process.setPipeDirection(STDIN_FILENO, SubProcess::ParentToChild);
+    m_process.setPipeDirection(STDOUT_FILENO, SubProcess::ChildToParent);
+    m_process.spawn("ssh", makeArgs());
 
-    // RSA
-    (pubkey = homedir).appendPath(".ssh").appendPath("id_rsa.pub");
-    (privkey = homedir).appendPath(".ssh").appendPath("id_rsa");
-    if (!authenticated && pubkey.exists() && privkey.exists()) {
-        Debug::debug()->dbg("Using private key %s and public key %s",
-                privkey.c_str(), pubkey.c_str());
-
-        ret = libssh2_userauth_publickey_fromfile(m_sshSession,
-                username.c_str(), pubkey.c_str(), privkey.c_str(),
-                password.c_str());
-        if (ret == 0)
-            authenticated = true;
-        else
-            Debug::debug()->dbg("id_rsa: "
-                "libssh2_userauth_publickey_fromfile() failed with "+
-                Stringutil::number2string(ret) + ".");
-    }
-
-    // password
-    if (!authenticated) {
-        Debug::debug()->dbg("Using password auth");
-
-        ret = libssh2_userauth_password(m_sshSession, username.c_str(),
-            password.c_str());
-        if (ret == 0)
-            authenticated = true;
-        else
-            Debug::debug()->dbg("libssh2_userauth_password() failed with "+
-                Stringutil::number2string(ret) + ".");
-    }
-
-    if (!authenticated) {
-        close();
-        throw KError("SSH authentication failed.");
-    }
-
-    // SFTP session
-    m_sftp = libssh2_sftp_init(m_sshSession);
-    if (!m_sftp) {
-        close();
-        throw KError("libssh2_sftp_init() failed with "+
-            Stringutil::number2string(ret) + ".");
-    }
-
-    FilePath fp = parser.getPath();
-    mkdir(fp.appendPath(subdir), true);
+    m_fdreq = m_process.getPipeFD(STDIN_FILENO);
+    m_fdresp = m_process.getPipeFD(STDOUT_FILENO);
 }
 
 /* -------------------------------------------------------------------------- */
@@ -409,62 +273,14 @@ SFTPTransfer::~SFTPTransfer()
 {
     Debug::debug()->trace("SFTPTransfer::~SFTPTransfer()");
 
-    close();
-}
-
-// -----------------------------------------------------------------------------
-bool SFTPTransfer::exists(const string &file)
-    throw (KError)
-{
-    Debug::debug()->trace("SFTPTransfer::exists(%s)", file.c_str());
-
-    LIBSSH2_SFTP_ATTRIBUTES attrs;
-    int ret = libssh2_sftp_stat(m_sftp, file.c_str(), &attrs);
-
-    if (ret != 0) {
-        int errorcode = libssh2_sftp_last_error(m_sftp);
-        if (errorcode == LIBSSH2_FX_NO_SUCH_FILE)
-            return false;
-        else
-            throw KSFTPError("libssh2_sftp_stat on " + file + " failed.",
-                errorcode);
-    }
-
-    return true;
-}
-
-// -----------------------------------------------------------------------------
-void SFTPTransfer::mkdir(const FilePath &dir, bool recursive)
-    throw (KError)
-{
-    Debug::debug()->trace("SFTPTransfer::mkdir(%s, %d)",
-        dir.c_str(), int(recursive));
-
-    if (!recursive) {
-        if (!exists(dir)) {
-            int ret = libssh2_sftp_mkdir(m_sftp, dir.c_str(), 0755);
-            if (ret != 0)
-                throw KSFTPError("mkdir of " + dir + " failed.",
-                    libssh2_sftp_last_error(m_sftp));
-        }
-    } else {
-        string directory = dir;
-
-        // remove trailing '/' if there are any
-        while (directory[directory.size()-1] == '/')
-            directory = directory.substr(0, directory.size()-1);
-
-        string::size_type current_slash = 0;
-
-        while (true) {
-            current_slash = directory.find('/', current_slash+1);
-            if (current_slash == string::npos) {
-                mkdir(directory, false);
-                break;
-            }
-
-            mkdir(directory.substr(0, current_slash), false);
-        }
+    if (m_process.getChildPID() != -1) {
+	close(m_fdreq);
+	close(m_fdresp);
+
+	int status = m_process.wait();
+	if (status != 0)
+	    throw KError("SFTPTransfer::~SFTPTransfer: ssh command failed"
+			 " with status " + Stringutil::number2string(status));
     }
 }
 
@@ -477,73 +293,32 @@ void SFTPTransfer::perform(DataProvider
     Debug::debug()->trace("SFTPTransfer::perform(%p, [ \"%s\"%s ])",
 	dataprovider, target_files.front().c_str(),
 	target_files.size() > 1 ? ", ..." : "");
+}
 
-    bool prepared = false;
-    if (directSave)
-        *directSave = false;
-
-    RootDirURLVector &urlv = getURLVector();
-    const RootDirURL &parser = urlv.front();
-
-    LIBSSH2_SFTP_HANDLE  *handle = NULL;
-    FilePath file = parser.getPath();
-    file.appendPath(getSubDir()).appendPath(target_files.front());
-
-    Debug::debug()->dbg("Using target file %s.", file.c_str());
-
-    try {
-        handle = libssh2_sftp_open(m_sftp, file.c_str(),
-            LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC, 0644);
-        if (!handle)
-            throw KSFTPError("Cannot create file " + file + " remotely.",
-                libssh2_sftp_last_error(m_sftp));
-
-        dataprovider->prepare();
-        prepared = true;
+/* -------------------------------------------------------------------------- */
+StringVector SFTPTransfer::makeArgs(void)
+{
+    const RootDirURL &target = getURLVector().front();
+    StringVector ret;
 
-        while (true) {
-            size_t read_data = dataprovider->getData(m_buffer, BUFSIZ);
+    ret.push_back("-F");
+    ret.push_back("/kdump/.ssh/config");
 
-            // finished?
-            if (read_data == 0)
-                break;
+    ret.push_back("-l");
+    ret.push_back(target.getUsername());
 
-            size_t ret = libssh2_sftp_write(handle, m_buffer, read_data);
-            if (ret != read_data)
-                throw KSFTPError("SFTPTransfer::perform: "
-                    "libssh2_sftp_write() failed.",
-                    libssh2_sftp_last_error(m_sftp));
-        }
-    } catch (...) {
-        if (handle)
-            libssh2_sftp_close(handle);
-        close();
-        if (prepared)
-            dataprovider->finish();
-        throw;
+    int port = target.getPort();
+    if (port != -1) {
+	ret.push_back("-p");
+	ret.push_back(Stringutil::number2string(port));
     }
 
-    if (handle)
-        libssh2_sftp_close(handle);
-    dataprovider->finish();
-}
-
+    ret.push_back("-s");
 
-/* -------------------------------------------------------------------------- */
-void SFTPTransfer::close()
-    throw ()
-{
-    Debug::debug()->trace("SFTPTransfer::close()");
+    ret.push_back(target.getHostname());
+    ret.push_back("sftp");
 
-    if (m_sshSession) {
-        libssh2_session_disconnect(m_sshSession, "Normal Shutdown.");
-        libssh2_session_free(m_sshSession);
-        m_sshSession = NULL;
-    }
-    delete m_socket;
-    m_socket = NULL;
+    return ret;
 }
 
-#endif // HAVE_LIBSSH2
-
 //}}}
--- a/kdumptool/sshtransfer.h
+++ b/kdumptool/sshtransfer.h
@@ -27,11 +27,6 @@
 #include "socket.h"
 #include "transfer.h"
 
-#if HAVE_LIBSSH2
-#   include <libssh2.h>
-#   include <libssh2_sftp.h>
-#endif
-
 //{{{ SSHTransfer --------------------------------------------------------------
 
 /**
@@ -123,8 +118,6 @@ class SFTPPacket {
 //}}}
 //{{{ SFTPTransfer -------------------------------------------------------------
 
-#if HAVE_LIBSSH2
-
 /**
  * Transfers a file to SFTP (upload).
  */
@@ -156,26 +149,13 @@ class SFTPTransfer : public URLTransfer
                      bool *directSave)
         throw (KError);
 
-    protected:
-        void close()
-        throw ();
-
-        void mkdir(const FilePath &dir, bool recursive)
-        throw (KError);
-
-        bool exists(const std::string &file)
-        throw (KError);
-
     private:
-        LIBSSH2_SESSION *m_sshSession;
-        LIBSSH2_SFTP *m_sftp;
-        Socket *m_socket;
-        char m_buffer[BUFSIZ];
+	SubProcess m_process;
+	int m_fdreq, m_fdresp;
 
+	StringVector makeArgs(void);
 };
 
-#endif // HAVE_LIBSSH2
-
 //}}}
 
 #endif /* SSHTRANSFER_H */
