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: Export the new symbol.
* src/rpc/virnetsocket.c: Add virNetSocketNewConnectLibSSH
* src/rpc/virnetsocket.h: Add header.
---
src/libvirt_private.syms | 1 +
src/rpc/virnetsocket.c | 137 +++++++++++++++++++++++++++++++++++++++++++++-
src/rpc/virnetsocket.h | 12 ++++
3 files changed, 149 insertions(+), 1 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index b15a8db..af286d2 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1301,6 +1301,7 @@ virNetSocketGetFD;
virNetSocketHasPassFD;
virNetSocketIsLocal;
virNetSocketListen;
+virNetSocketNewConnectLibSSH;
virNetSocketNewConnectTCP;
virNetSocketNewListenUNIX;
virNetSocketRecvFD;
diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c
index 30b8fe6..976a4ac 100644
--- a/src/rpc/virnetsocket.c
+++ b/src/rpc/virnetsocket.c
@@ -45,6 +45,10 @@
#include "passfd.h"
+#if HAVE_LIBSSH2
+# include "virnetlibsshcontext.h"
+#endif
+
#define VIR_FROM_THIS VIR_FROM_RPC
#define virNetError(code, ...) \
@@ -84,6 +88,9 @@ struct _virNetSocket {
size_t saslEncodedLength;
size_t saslEncodedOffset;
#endif
+#if HAVE_LIBSSH2
+ virNetLibSSHSessionPtr sshSession;
+#endif
};
@@ -676,6 +683,98 @@ int virNetSocketNewConnectSSH(const char *nodename,
return virNetSocketNewConnectCommand(cmd, retsock);
}
+#if HAVE_LIBSSH2
+int virNetSocketNewConnectLibSSH(const char *host,
+ const char *port,
+ const char *username,
+ const char *password,
+ const char *command,
+ const char *knownHostsFile,
+ const char *hostkeyVerify,
+ const char *privkey,
+ virConnectAuthPtr auth,
+ virNetSocketPtr *retsock)
+{
+ virNetSocketPtr sock = NULL;
+ virNetLibSSHSessionPtr sess = NULL;
+ int ret = -1;
+ int portN;
+ virNetLibSSHHostkeyVerify verify = VIR_NET_LIBSSH_HOSTKEY_VERIFY_NORMAL;
+
+
+ if ((ret = virNetSocketNewConnectTCP(host, port, &sock)) < 0)
+ goto error;
+
+ sess = virNetLibSSHSessionNew();
+ if (!sess){
+ ret = -1;
+ goto error;
+ }
+
+ /* configure libssh2 session */
+ if ((ret = virNetLibSSHSessionSetCredentials(sess,
+ username,
+ password)) != 0)
+ goto error;
+
+ virNetLibSSHSessionSetAuthCallback(sess, auth); /* allways succeeds */
+
+
+ if ((ret = virNetLibSSHSessionSetChannelCommand(sess, command)) != 0)
+ goto error;
+
+ if ((ret = virNetLibSSHSessionSetPrivateKey(sess, privkey)) != 0)
+ goto error;
+
+ /* port was verified while opening the socket */
+ sscanf(port, "%d", &portN);
+
+ if (hostkeyVerify) {
+ if (STRCASEEQ("auto", hostkeyVerify))
+ verify = VIR_NET_LIBSSH_HOSTKEY_VERIFY_AUTO_ADD;
+ else if (STRCASEEQ("ignore", hostkeyVerify))
+ verify = VIR_NET_LIBSSH_HOSTKEY_VERIFY_IGNORE;
+ }
+
+ if ((ret = virNetLibSSHSessionSetHostKeyVerification(sess,
+ host,
+ portN,
+ knownHostsFile,
+ false,
+ verify) != 0))
+ goto error;
+
+ /* connect to the host using ssh */
+ if ((ret = virNetLibSSHSessionConnect(sess, virNetSocketGetFD(sock))) != 0)
+ goto error;
+
+ sock->sshSession = sess;
+ *retsock = sock;
+
+ return 0;
+
+error:
+ virNetSocketFree(sock);
+ virNetLibSSHSessionFree(sess);
+ return ret;
+}
+#else
+int virNetSocketNewConnectLibSSH(const char *host ATTRIBUTE_UNUSED,
+ const char *port ATTRIBUTE_UNUSED,
+ const char *username ATTRIBUTE_UNUSED,
+ const char *password ATTRIBUTE_UNUSED,
+ const char *command ATTRIBUTE_UNUSED,
+ const char *knownHostsFile ATTRIBUTE_UNUSED,
+ const char *hostkeyVerify ATTRIBUTE_UNUSED,
+ const char *privkey ATTRIBUTE_UNUSED,
+ virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+ virNetSocketPtr *retsock ATTRIBUTE_UNUSED)
+{
+ virReportSystemError(ENOSYS,
+ _("libssh2 transport support was not enabled in this
build"));
+ return -1;
+}
+#endif /* HAVE_LIBSSH2 */
int virNetSocketNewConnectExternal(const char **cmdargv,
virNetSocketPtr *retsock)
@@ -741,6 +840,10 @@ void virNetSocketFree(virNetSocketPtr sock)
virNetSASLSessionFree(sock->saslSession);
#endif
+#if HAVE_LIBSSH2
+ virNetLibSSHSessionFree(sock->sshSession);
+#endif
+
VIR_FORCE_CLOSE(sock->fd);
VIR_FORCE_CLOSE(sock->errfd);
@@ -922,6 +1025,12 @@ bool virNetSocketHasCachedData(virNetSocketPtr sock
ATTRIBUTE_UNUSED)
{
bool hasCached = false;
virMutexLock(&sock->lock);
+
+#if HAVE_LIBSSH2
+ if (virNetLibSSHHasCachedData(sock->sshSession))
+ hasCached = true;
+#endif
+
#if HAVE_SASL
if (sock->saslDecoded)
hasCached = true;
@@ -930,11 +1039,32 @@ bool virNetSocketHasCachedData(virNetSocketPtr sock
ATTRIBUTE_UNUSED)
return hasCached;
}
+#if HAVE_LIBSSH2
+static ssize_t virNetSocketLibSSHRead(virNetSocketPtr sock,
+ char *buf,
+ size_t len)
+{
+ return virNetLibSSHChannelRead(sock->sshSession, buf, len);
+}
+
+static ssize_t virNetSocketLibSSHWrite(virNetSocketPtr sock,
+ const char *buf,
+ size_t len)
+{
+ return virNetLibSSHChannelWrite(sock->sshSession, buf, len);
+}
+#endif
static ssize_t virNetSocketReadWire(virNetSocketPtr sock, char *buf, size_t len)
{
char *errout = NULL;
ssize_t ret;
+
+#if HAVE_LIBSSH2
+ if (sock->sshSession)
+ return virNetSocketLibSSHRead(sock, buf, len);
+#endif
+
reread:
if (sock->tlsSession &&
virNetTLSSessionGetHandshakeStatus(sock->tlsSession) ==
@@ -983,6 +1113,12 @@ reread:
static ssize_t virNetSocketWriteWire(virNetSocketPtr sock, const char *buf, size_t len)
{
ssize_t ret;
+
+#if HAVE_LIBSSH2
+ if (sock->sshSession)
+ return virNetSocketLibSSHWrite(sock, buf, len);
+#endif
+
rewrite:
if (sock->tlsSession &&
virNetTLSSessionGetHandshakeStatus(sock->tlsSession) ==
@@ -1111,7 +1247,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 e444aef..15b860b 100644
--- a/src/rpc/virnetsocket.h
+++ b/src/rpc/virnetsocket.h
@@ -74,6 +74,17 @@ int virNetSocketNewConnectSSH(const char *nodename,
const char *path,
virNetSocketPtr *addr);
+int virNetSocketNewConnectLibSSH(const char *host,
+ const char *port,
+ const char *username,
+ const char *password,
+ const char *command,
+ const char *knownHostsFile,
+ const char *hostkeyVerify,
+ const char *privkey,
+ virConnectAuthPtr auth,
+ virNetSocketPtr *retsock);
+
int virNetSocketNewConnectExternal(const char **cmdargv,
virNetSocketPtr *addr);
@@ -101,6 +112,7 @@ int virNetSocketRecvFD(virNetSocketPtr sock, int *fd);
void virNetSocketSetTLSSession(virNetSocketPtr sock,
virNetTLSSessionPtr sess);
+
# ifdef HAVE_SASL
void virNetSocketSetSASLSession(virNetSocketPtr sock,
virNetSASLSessionPtr sess);
--
1.7.3.4