[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCHv2 2/4] libssh2_transport: add ssh context support to virNetSocket



This patch enables virNetSocket to be used as an ssh client when
properly configured.

Fucntion virNetSocketNewConnectLibSSH() is added, that takes all needed
parameters and creates a libssh2 session context and performs steps
needed to open the connection.
---
 src/libvirt_private.syms |    1 +
 src/rpc/virnetsocket.c   |  178 +++++++++++++++++++++++++++++++++++++++++++++-
 src/rpc/virnetsocket.h   |   13 ++++
 3 files changed, 191 insertions(+), 1 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index c023dbf..479613f 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1575,6 +1575,7 @@ virNetSocketListen;
 virNetSocketLocalAddrString;
 virNetSocketNewConnectCommand;
 virNetSocketNewConnectExternal;
+virNetSocketNewConnectLibSSH2;
 virNetSocketNewConnectSSH;
 virNetSocketNewConnectTCP;
 virNetSocketNewConnectUNIX;
diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c
index b6f156b..5bf4b47 100644
--- a/src/rpc/virnetsocket.c
+++ b/src/rpc/virnetsocket.c
@@ -47,6 +47,10 @@

 #include "passfd.h"

+#if HAVE_LIBSSH2
+# include "virnetlibssh2session.h"
+#endif
+
 #define VIR_FROM_THIS VIR_FROM_RPC


@@ -83,6 +87,9 @@ struct _virNetSocket {
     size_t saslEncodedLength;
     size_t saslEncodedOffset;
 #endif
+#if HAVE_LIBSSH2
+    virNetLibSSH2SessionPtr sshSession;
+#endif
 };


@@ -705,6 +712,139 @@ int virNetSocketNewConnectSSH(const char *nodename,
     return virNetSocketNewConnectCommand(cmd, retsock);
 }

+#if HAVE_LIBSSH2
+int
+virNetSocketNewConnectLibSSH2(const char *host,
+                              const char *port,
+                              const char *username,
+                              const char *password,
+                              const char *privkey,
+                              const char *knownHosts,
+                              const char *knownHostsVerify,
+                              const char *authMethods,
+                              const char *command,
+                              virConnectAuthPtr auth,
+                              virNetSocketPtr *retsock)
+{
+    virNetSocketPtr sock = NULL;
+    virNetLibSSH2SessionPtr sess = NULL;
+    unsigned int verify;
+    int ret = -1;
+    int portN;
+
+    char *authMethodNext = NULL;
+    char *authMethodsCopy = NULL;
+    char *authMethod;
+
+    /* port number will be verified while opening the socket */
+    if (virStrToLong_i(port, NULL, 10, &portN) < 0) {
+        virReportError(VIR_ERR_LIBSSH2_ERROR, "%s",
+                       _("Failed to parse port number"));
+        goto error;
+    }
+
+    /* create ssh session context */
+    if (!(sess = virNetLibSSH2SessionNew()))
+        goto error;
+
+    /* set ssh session parameters */
+    if (virNetLibSSH2SessionAuthSetCallback(sess, auth) != 0)
+        goto error;
+
+    if (STRCASEEQ("auto", knownHostsVerify))
+        verify = VIR_NET_LIBSSH2_HOSTKEY_VERIFY_AUTO_ADD;
+    else if (STRCASEEQ("ignore", knownHostsVerify))
+        verify = VIR_NET_LIBSSH2_HOSTKEY_VERIFY_IGNORE;
+    else if (STRCASEEQ("normal", knownHostsVerify))
+        verify = VIR_NET_LIBSSH2_HOSTKEY_VERIFY_NORMAL;
+    else {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("Invalid host key verification method: '%s'"),
+                       knownHostsVerify);
+        goto error;
+    }
+
+    if (virNetLibSSH2SessionSetHostKeyVerification(sess,
+                                                  host,
+                                                  portN,
+                                                  knownHosts,
+                                                  false,
+                                                  verify) != 0)
+        goto error;
+
+    if (virNetLibSSH2SessionSetChannelCommand(sess, command) != 0)
+        goto error;
+
+    if (!(authMethodNext = authMethodsCopy = strdup(authMethods))) {
+        virReportOOMError();
+        goto error;
+    }
+
+    while ((authMethod = strsep(&authMethodNext, ","))) {
+        if (STRCASEEQ(authMethod, "keyboard-interactive"))
+            ret = virNetLibSSH2SessionAuthAddKeyboardAuth(sess, username, -1);
+        else if (STRCASEEQ(authMethod, "password"))
+            ret = virNetLibSSH2SessionAuthAddPasswordAuth(sess,
+                                                         username,
+                                                         password);
+        else if (STRCASEEQ(authMethod, "privkey"))
+            ret = virNetLibSSH2SessionAuthAddPrivKeyAuth(sess,
+                                                        username,
+                                                        privkey,
+                                                        NULL);
+        else if (STRCASEEQ(authMethod, "agent"))
+            ret = virNetLibSSH2SessionAuthAddAgentAuth(sess, username);
+        else {
+            virReportError(VIR_ERR_INVALID_ARG,
+                           _("Invalid authentication method: '%s'"),
+                           authMethod);
+            ret = -1;
+            goto error;
+        }
+
+        if (ret != 0)
+            goto error;
+    }
+
+    /* connect to remote server */
+    if ((ret = virNetSocketNewConnectTCP(host, port, &sock)) < 0)
+        goto error;
+
+    /* connect to the host using ssh */
+    if ((ret = virNetLibSSH2SessionConnect(sess, virNetSocketGetFD(sock))) != 0)
+        goto error;
+
+    sock->sshSession = sess;
+    *retsock = sock;
+
+    VIR_FREE(authMethodsCopy);
+    return 0;
+
+error:
+    virObjectUnref(sock);
+    virObjectUnref(sess);
+    VIR_FREE(authMethodsCopy);
+    return ret;
+}
+#else
+int
+virNetSocketNewConnectLibSSH2(const char *host ATTRIBUTE_UNUSED,
+                              const char *port ATTRIBUTE_UNUSED,
+                              const char *username ATTRIBUTE_UNUSED,
+                              const char *password ATTRIBUTE_UNUSED,
+                              const char *privkey ATTRIBUTE_UNUSED,
+                              const char *knownHosts ATTRIBUTE_UNUSED,
+                              const char *knownHostsVerify ATTRIBUTE_UNUSED,
+                              const char *authMethods ATTRIBUTE_UNUSED,
+                              const char *command ATTRIBUTE_UNUSED,
+                              virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+                              virNetSocketPtr *retsock ATTRIBUTE_UNUSED)
+{
+    virReportSystemError(ENOSYS, "%s",
+                         _("libssh2 transport support was not enabled"));
+    return -1;
+}
+#endif /* HAVE_LIBSSH2 */

 int virNetSocketNewConnectExternal(const char **cmdargv,
                                    virNetSocketPtr *retsock)
@@ -747,6 +887,10 @@ void virNetSocketDispose(void *obj)
     virObjectUnref(sock->saslSession);
 #endif

+#if HAVE_LIBSSH2
+    virObjectUnref(sock->sshSession);
+#endif
+
     VIR_FORCE_CLOSE(sock->fd);
     VIR_FORCE_CLOSE(sock->errfd);

@@ -926,6 +1070,12 @@ bool virNetSocketHasCachedData(virNetSocketPtr sock ATTRIBUTE_UNUSED)
 {
     bool hasCached = false;
     virMutexLock(&sock->lock);
+
+#if HAVE_LIBSSH2
+    if (virNetLibSSH2SessionHasCachedData(sock->sshSession))
+        hasCached = true;
+#endif
+
 #if HAVE_SASL
     if (sock->saslDecoded)
         hasCached = true;
@@ -934,6 +1084,21 @@ bool virNetSocketHasCachedData(virNetSocketPtr sock ATTRIBUTE_UNUSED)
     return hasCached;
 }

+#if HAVE_LIBSSH2
+static ssize_t virNetSocketLibSSH2Read(virNetSocketPtr sock,
+                                       char *buf,
+                                       size_t len)
+{
+    return virNetLibSSH2ChannelRead(sock->sshSession, buf, len);
+}
+
+static ssize_t virNetSocketLibSSH2Write(virNetSocketPtr sock,
+                                        const char *buf,
+                                        size_t len)
+{
+    return virNetLibSSH2ChannelWrite(sock->sshSession, buf, len);
+}
+#endif

 bool virNetSocketHasPendingData(virNetSocketPtr sock ATTRIBUTE_UNUSED)
 {
@@ -952,6 +1117,12 @@ static ssize_t virNetSocketReadWire(virNetSocketPtr sock, char *buf, size_t len)
 {
     char *errout = NULL;
     ssize_t ret;
+
+#if HAVE_LIBSSH2
+    if (sock->sshSession)
+        return virNetSocketLibSSH2Read(sock, buf, len);
+#endif
+
 reread:
     if (sock->tlsSession &&
         virNetTLSSessionGetHandshakeStatus(sock->tlsSession) ==
@@ -1001,6 +1172,12 @@ reread:
 static ssize_t virNetSocketWriteWire(virNetSocketPtr sock, const char *buf, size_t len)
 {
     ssize_t ret;
+
+#if HAVE_LIBSSH2
+    if (sock->sshSession)
+        return virNetSocketLibSSH2Write(sock, buf, len);
+#endif
+
 rewrite:
     if (sock->tlsSession &&
         virNetTLSSessionGetHandshakeStatus(sock->tlsSession) ==
@@ -1129,7 +1306,6 @@ static ssize_t virNetSocketWriteSASL(virNetSocketPtr sock, const char *buf, size
 }
 #endif

-
 ssize_t virNetSocketRead(virNetSocketPtr sock, char *buf, size_t len)
 {
     ssize_t ret;
diff --git a/src/rpc/virnetsocket.h b/src/rpc/virnetsocket.h
index cc3f912..fc5e17f 100644
--- a/src/rpc/virnetsocket.h
+++ b/src/rpc/virnetsocket.h
@@ -75,6 +75,18 @@ int virNetSocketNewConnectSSH(const char *nodename,
                               const char *path,
                               virNetSocketPtr *addr);

+int virNetSocketNewConnectLibSSH2(const char *host,
+                                  const char *port,
+                                  const char *username,
+                                  const char *password,
+                                  const char *privkey,
+                                  const char *knownHosts,
+                                  const char *knownHostsVerify,
+                                  const char *authMethods,
+                                  const char *command,
+                                  virConnectAuthPtr auth,
+                                  virNetSocketPtr *retsock);
+
 int virNetSocketNewConnectExternal(const char **cmdargv,
                                    virNetSocketPtr *addr);

@@ -103,6 +115,7 @@ int virNetSocketRecvFD(virNetSocketPtr sock, int *fd);

 void virNetSocketSetTLSSession(virNetSocketPtr sock,
                                virNetTLSSessionPtr sess);
+
 # ifdef HAVE_SASL
 void virNetSocketSetSASLSession(virNetSocketPtr sock,
                                 virNetSASLSessionPtr sess);
-- 
1.7.8.6


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]