mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-25 07:05:28 +00:00
libssh2_transport: add ssh context support to virNetSocket
This patch enables virNetSocket to be used as an ssh client when properly configured. This patch adds function virNetSocketNewConnectLibSSH2() that takes all needed parameters and creates a libssh2 session and performs steps needed to open the connection and then create a virNetSocket that seamlesly encapsulates the communication.
This commit is contained in:
parent
1193fc5f44
commit
637ea54274
@ -1595,6 +1595,7 @@ virNetSocketListen;
|
|||||||
virNetSocketLocalAddrString;
|
virNetSocketLocalAddrString;
|
||||||
virNetSocketNewConnectCommand;
|
virNetSocketNewConnectCommand;
|
||||||
virNetSocketNewConnectExternal;
|
virNetSocketNewConnectExternal;
|
||||||
|
virNetSocketNewConnectLibSSH2;
|
||||||
virNetSocketNewConnectSSH;
|
virNetSocketNewConnectSSH;
|
||||||
virNetSocketNewConnectTCP;
|
virNetSocketNewConnectTCP;
|
||||||
virNetSocketNewConnectUNIX;
|
virNetSocketNewConnectUNIX;
|
||||||
|
@ -47,6 +47,10 @@
|
|||||||
|
|
||||||
#include "passfd.h"
|
#include "passfd.h"
|
||||||
|
|
||||||
|
#if HAVE_LIBSSH2
|
||||||
|
# include "virnetsshsession.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define VIR_FROM_THIS VIR_FROM_RPC
|
#define VIR_FROM_THIS VIR_FROM_RPC
|
||||||
|
|
||||||
|
|
||||||
@ -83,6 +87,9 @@ struct _virNetSocket {
|
|||||||
size_t saslEncodedLength;
|
size_t saslEncodedLength;
|
||||||
size_t saslEncodedOffset;
|
size_t saslEncodedOffset;
|
||||||
#endif
|
#endif
|
||||||
|
#if HAVE_LIBSSH2
|
||||||
|
virNetSSHSessionPtr sshSession;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -725,6 +732,139 @@ int virNetSocketNewConnectSSH(const char *nodename,
|
|||||||
return virNetSocketNewConnectCommand(cmd, retsock);
|
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;
|
||||||
|
virNetSSHSessionPtr 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_SSH, "%s",
|
||||||
|
_("Failed to parse port number"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create ssh session context */
|
||||||
|
if (!(sess = virNetSSHSessionNew()))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* set ssh session parameters */
|
||||||
|
if (virNetSSHSessionAuthSetCallback(sess, auth) != 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (STRCASEEQ("auto", knownHostsVerify))
|
||||||
|
verify = VIR_NET_SSH_HOSTKEY_VERIFY_AUTO_ADD;
|
||||||
|
else if (STRCASEEQ("ignore", knownHostsVerify))
|
||||||
|
verify = VIR_NET_SSH_HOSTKEY_VERIFY_IGNORE;
|
||||||
|
else if (STRCASEEQ("normal", knownHostsVerify))
|
||||||
|
verify = VIR_NET_SSH_HOSTKEY_VERIFY_NORMAL;
|
||||||
|
else {
|
||||||
|
virReportError(VIR_ERR_INVALID_ARG,
|
||||||
|
_("Invalid host key verification method: '%s'"),
|
||||||
|
knownHostsVerify);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virNetSSHSessionSetHostKeyVerification(sess,
|
||||||
|
host,
|
||||||
|
portN,
|
||||||
|
knownHosts,
|
||||||
|
false,
|
||||||
|
verify) != 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (virNetSSHSessionSetChannelCommand(sess, command) != 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!(authMethodNext = authMethodsCopy = strdup(authMethods))) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((authMethod = strsep(&authMethodNext, ","))) {
|
||||||
|
if (STRCASEEQ(authMethod, "keyboard-interactive"))
|
||||||
|
ret = virNetSSHSessionAuthAddKeyboardAuth(sess, username, -1);
|
||||||
|
else if (STRCASEEQ(authMethod, "password"))
|
||||||
|
ret = virNetSSHSessionAuthAddPasswordAuth(sess,
|
||||||
|
username,
|
||||||
|
password);
|
||||||
|
else if (STRCASEEQ(authMethod, "privkey"))
|
||||||
|
ret = virNetSSHSessionAuthAddPrivKeyAuth(sess,
|
||||||
|
username,
|
||||||
|
privkey,
|
||||||
|
NULL);
|
||||||
|
else if (STRCASEEQ(authMethod, "agent"))
|
||||||
|
ret = virNetSSHSessionAuthAddAgentAuth(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 = virNetSSHSessionConnect(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,
|
int virNetSocketNewConnectExternal(const char **cmdargv,
|
||||||
virNetSocketPtr *retsock)
|
virNetSocketPtr *retsock)
|
||||||
@ -767,6 +907,10 @@ void virNetSocketDispose(void *obj)
|
|||||||
virObjectUnref(sock->saslSession);
|
virObjectUnref(sock->saslSession);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_LIBSSH2
|
||||||
|
virObjectUnref(sock->sshSession);
|
||||||
|
#endif
|
||||||
|
|
||||||
VIR_FORCE_CLOSE(sock->fd);
|
VIR_FORCE_CLOSE(sock->fd);
|
||||||
VIR_FORCE_CLOSE(sock->errfd);
|
VIR_FORCE_CLOSE(sock->errfd);
|
||||||
|
|
||||||
@ -946,6 +1090,12 @@ bool virNetSocketHasCachedData(virNetSocketPtr sock ATTRIBUTE_UNUSED)
|
|||||||
{
|
{
|
||||||
bool hasCached = false;
|
bool hasCached = false;
|
||||||
virMutexLock(&sock->lock);
|
virMutexLock(&sock->lock);
|
||||||
|
|
||||||
|
#if HAVE_LIBSSH2
|
||||||
|
if (virNetSSHSessionHasCachedData(sock->sshSession))
|
||||||
|
hasCached = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if HAVE_SASL
|
#if HAVE_SASL
|
||||||
if (sock->saslDecoded)
|
if (sock->saslDecoded)
|
||||||
hasCached = true;
|
hasCached = true;
|
||||||
@ -954,6 +1104,21 @@ bool virNetSocketHasCachedData(virNetSocketPtr sock ATTRIBUTE_UNUSED)
|
|||||||
return hasCached;
|
return hasCached;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if HAVE_LIBSSH2
|
||||||
|
static ssize_t virNetSocketLibSSH2Read(virNetSocketPtr sock,
|
||||||
|
char *buf,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
return virNetSSHChannelRead(sock->sshSession, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t virNetSocketLibSSH2Write(virNetSocketPtr sock,
|
||||||
|
const char *buf,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
return virNetSSHChannelWrite(sock->sshSession, buf, len);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool virNetSocketHasPendingData(virNetSocketPtr sock ATTRIBUTE_UNUSED)
|
bool virNetSocketHasPendingData(virNetSocketPtr sock ATTRIBUTE_UNUSED)
|
||||||
{
|
{
|
||||||
@ -972,6 +1137,12 @@ static ssize_t virNetSocketReadWire(virNetSocketPtr sock, char *buf, size_t len)
|
|||||||
{
|
{
|
||||||
char *errout = NULL;
|
char *errout = NULL;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
|
#if HAVE_LIBSSH2
|
||||||
|
if (sock->sshSession)
|
||||||
|
return virNetSocketLibSSH2Read(sock, buf, len);
|
||||||
|
#endif
|
||||||
|
|
||||||
reread:
|
reread:
|
||||||
if (sock->tlsSession &&
|
if (sock->tlsSession &&
|
||||||
virNetTLSSessionGetHandshakeStatus(sock->tlsSession) ==
|
virNetTLSSessionGetHandshakeStatus(sock->tlsSession) ==
|
||||||
@ -1021,6 +1192,12 @@ reread:
|
|||||||
static ssize_t virNetSocketWriteWire(virNetSocketPtr sock, const char *buf, size_t len)
|
static ssize_t virNetSocketWriteWire(virNetSocketPtr sock, const char *buf, size_t len)
|
||||||
{
|
{
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
|
#if HAVE_LIBSSH2
|
||||||
|
if (sock->sshSession)
|
||||||
|
return virNetSocketLibSSH2Write(sock, buf, len);
|
||||||
|
#endif
|
||||||
|
|
||||||
rewrite:
|
rewrite:
|
||||||
if (sock->tlsSession &&
|
if (sock->tlsSession &&
|
||||||
virNetTLSSessionGetHandshakeStatus(sock->tlsSession) ==
|
virNetTLSSessionGetHandshakeStatus(sock->tlsSession) ==
|
||||||
@ -1149,7 +1326,6 @@ static ssize_t virNetSocketWriteSASL(virNetSocketPtr sock, const char *buf, size
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
ssize_t virNetSocketRead(virNetSocketPtr sock, char *buf, size_t len)
|
ssize_t virNetSocketRead(virNetSocketPtr sock, char *buf, size_t len)
|
||||||
{
|
{
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
@ -78,6 +78,18 @@ int virNetSocketNewConnectSSH(const char *nodename,
|
|||||||
const char *path,
|
const char *path,
|
||||||
virNetSocketPtr *addr);
|
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,
|
int virNetSocketNewConnectExternal(const char **cmdargv,
|
||||||
virNetSocketPtr *addr);
|
virNetSocketPtr *addr);
|
||||||
|
|
||||||
@ -106,6 +118,7 @@ int virNetSocketRecvFD(virNetSocketPtr sock, int *fd);
|
|||||||
|
|
||||||
void virNetSocketSetTLSSession(virNetSocketPtr sock,
|
void virNetSocketSetTLSSession(virNetSocketPtr sock,
|
||||||
virNetTLSSessionPtr sess);
|
virNetTLSSessionPtr sess);
|
||||||
|
|
||||||
# ifdef HAVE_SASL
|
# ifdef HAVE_SASL
|
||||||
void virNetSocketSetSASLSession(virNetSocketPtr sock,
|
void virNetSocketSetSASLSession(virNetSocketPtr sock,
|
||||||
virNetSASLSessionPtr sess);
|
virNetSASLSessionPtr sess);
|
||||||
|
Loading…
Reference in New Issue
Block a user