libssh2_transport: add main libssh2 transport implementation

This patch adds helper functions that enable us to use libssh2 in
conjunction with libvirt's virNetSockets for ssh transport instead of
spawning "ssh" client process.

This implemetation supports tunneled plaintext, keyboard-interactive,
private key, ssh agent based and null authentication. Libvirt's Auth
callback is used for interaction with the user. (Keyboard interactive
authentication, adding of host keys, private key passphrases). This
enables seamless integration into the application using libvirt. No
helpers as "ssh-askpass" are needed.

Reading and writing of OpenSSH style "known_hosts" files is supported.

Communication is done using SSH exec channel, where the user may specify
arbitrary command to be executed on the remote side and reads and writes
to/from stdin/out are sent through the ssh channel. Usage of stderr is
not (yet) supported.
This commit is contained in:
Peter Krempa 2011-11-14 15:30:23 +01:00
parent 9136032a66
commit 1193fc5f44
8 changed files with 1636 additions and 6 deletions

View File

@ -112,6 +112,7 @@ OPENWSMAN_REQUIRED="2.2.3"
LIBPCAP_REQUIRED="1.0.0"
LIBNL_REQUIRED="1.1"
LIBSSH2_REQUIRED="1.0"
LIBSSH2_TRANSPORT_REQUIRED="1.3"
LIBBLKID_REQUIRED="2.17"
DBUS_REQUIRED="1.0.0"
@ -440,6 +441,8 @@ AC_ARG_WITH([console-lock-files],
(use auto for default paths on some platforms)
@<:@default=auto@:>@]),
[],[with_console_lock_files=auto])
AC_ARG_WITH([libssh2_transport],
AC_HELP_STRING([--with-libssh2_transport], [libssh2 location @<:@default=check@:>@]),[],[with_libssh2_transport=check])
dnl
dnl in case someone want to build static binaries
@ -1748,29 +1751,58 @@ AM_CONDITIONAL([WITH_UML], [test "$with_uml" = "yes"])
dnl
dnl check for libssh2 (PHYP)
dnl check for libssh2 (PHYP and libssh2 transport)
dnl
LIBSSH2_CFLAGS=""
LIBSSH2_LIBS=""
if test "$with_phyp" = "yes" || test "$with_phyp" = "check"; then
if test "$with_phyp" = "yes" || test "$with_phyp" = "check" ||
test "$with_libssh2_transport" = "yes" || test "$with_libssh2_transport" = "check"; then
PKG_CHECK_MODULES([LIBSSH2], [libssh2 >= $LIBSSH2_REQUIRED], [
with_phyp=yes
if test "$with_phyp" = "check"; then
with_phyp=yes
fi
if $PKG_CONFIG "libssh2 >= $LIBSSH2_TRANSPORT_REQUIRED"; then
if test "$with_libssh2_transport" = "check"; then
with_libssh2_transport=yes
fi
else
if test "$with_libssh2_transport" = "check"; then
with_libssh2_transport=no
AC_MSG_NOTICE([libssh2 >= $LIBSSH2_TRANSPORT_REQUIRED is required for libssh2 transport])
fi
if test "$with_libssh2_transport" = "yes"; then
AC_MSG_ERROR([libssh2 >= $LIBSSH2_TRANSPORT_REQUIRED is required for libssh2 transport])
fi
fi
], [
if test "$with_phyp" = "check"; then
with_phyp=no
AC_MSG_NOTICE([libssh2 is required for Phyp driver, disabling it])
else
fi
if test "$with_phyp" = "yes"; then
AC_MSG_ERROR([libssh2 >= $LIBSSH2_REQUIRED is required for Phyp driver])
fi
if test "$with_libssh2_transport" = "check"; then
with_libssh2_transport=no
AC_MSG_NOTICE([libssh2 >= $LIBSSH2_TRANSPORT_REQUIRED is required for libssh2 transport])
fi
if test "$with_libssh2_transport" = "yes"; then
AC_MSG_ERROR([libssh2 >= $LIBSSH2_TRANSPORT_REQUIRED is required for libssh2 transport])
fi
])
fi
if test "$with_phyp" = "yes"; then
AC_DEFINE_UNQUOTED([WITH_PHYP], 1, [whether IBM HMC / IVM driver is enabled])
fi
if test "$with_libssh2_transport" = "yes"; then
AC_DEFINE_UNQUOTED([HAVE_LIBSSH2], 1, [whether libssh2 transport is enabled])
fi
AM_CONDITIONAL([WITH_PHYP],[test "$with_phyp" = "yes"])
AM_CONDITIONAL([HAVE_LIBSSH2], [test "$with_libssh2_transport" = "yes"])
AC_SUBST([LIBSSH2_CFLAGS])
AC_SUBST([LIBSSH2_LIBS])

View File

@ -112,6 +112,8 @@ typedef enum {
VIR_FROM_PARALLELS = 48, /* Error from Parallels */
VIR_FROM_DEVICE = 49, /* Error from Device */
VIR_FROM_SSH = 50, /* Error from libssh2 connection transport */
# ifdef VIR_ENUM_SENTINELS
VIR_ERR_DOMAIN_LAST
# endif
@ -280,6 +282,7 @@ typedef enum {
VIR_ERR_BLOCK_COPY_ACTIVE = 83, /* action prevented by block copy job */
VIR_ERR_OPERATION_UNSUPPORTED = 84, /* The requested operation is not
supported */
VIR_ERR_SSH = 85, /* error in ssh transport driver */
} virErrorNumber;
/**

View File

@ -100,6 +100,7 @@ src/rpc/virnetserver.c
src/rpc/virnetserverclient.c
src/rpc/virnetservermdns.c
src/rpc/virnetserverprogram.c
src/rpc/virnetsshsession.c
src/rpc/virnettlscontext.c
src/secret/secret_driver.c
src/security/security_apparmor.c

View File

@ -1323,6 +1323,10 @@ if HAVE_SASL
USED_SYM_FILES += libvirt_sasl.syms
endif
if HAVE_LIBSSH2
USED_SYM_FILES += libvirt_libssh2.syms
endif
if WITH_ATOMIC_OPS_PTHREAD
USED_SYM_FILES += libvirt_atomic.syms
endif
@ -1339,7 +1343,8 @@ EXTRA_DIST += \
libvirt_qemu.syms \
libvirt_sasl.syms \
libvirt_vmx.syms \
libvirt_xenxs.syms
libvirt_xenxs.syms \
libvirt_libssh2.syms
GENERATED_SYM_FILES = libvirt.syms libvirt.def libvirt_qemu.def
@ -1518,6 +1523,13 @@ libvirt_net_rpc_la_SOURCES = \
rpc/virnettlscontext.h rpc/virnettlscontext.c \
rpc/virkeepaliveprotocol.h rpc/virkeepaliveprotocol.c \
rpc/virkeepalive.h rpc/virkeepalive.c
if HAVE_LIBSSH2
libvirt_net_rpc_la_SOURCES += \
rpc/virnetsshsession.h rpc/virnetsshsession.c
else
EXTRA_DIST += \
rpc/virnetsshsession.h rpc/virnetsshsession.c
endif
if HAVE_SASL
libvirt_net_rpc_la_SOURCES += \
rpc/virnetsaslcontext.h rpc/virnetsaslcontext.c
@ -1528,11 +1540,13 @@ endif
libvirt_net_rpc_la_CFLAGS = \
$(GNUTLS_CFLAGS) \
$(SASL_CFLAGS) \
$(LIBSSH2_CFLAGS) \
$(XDR_CFLAGS) \
$(AM_CFLAGS)
libvirt_net_rpc_la_LDFLAGS = \
$(GNUTLS_LIBS) \
$(SASL_LIBS) \
$(LIBSSH2_LIBS)\
$(AM_LDFLAGS) \
$(CYGWIN_EXTRA_LDFLAGS) \
$(MINGW_EXTRA_LDFLAGS)

18
src/libvirt_libssh2.syms Normal file
View File

@ -0,0 +1,18 @@
#
# ssh session - specific symbols
#
# virnetsshsession.h
#
virNetSSHChannelRead;
virNetSSHChannelWrite;
virNetSSHSessionAuthAddAgentAuth;
virNetSSHSessionAuthAddKeyboardAuth;
virNetSSHSessionAuthAddPasswordAuth;
virNetSSHSessionAuthAddPrivKeyAuth;
virNetSSHSessionAuthReset;
virNetSSHSessionAuthSetCallback;
virNetSSHSessionConnect;
virNetSSHSessionHasCachedData;
virNetSSHSessionSetChannelCommand;
virNetSSHSessionSetHostKeyVerification;

1472
src/rpc/virnetsshsession.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,83 @@
/*
* virnetsshsession.h: ssh transport provider based on libssh2
*
* Copyright (C) 2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; If not, see
* <http://www.gnu.org/licenses/>.
*
* Author: Peter Krempa <pkrempa@redhat.com>
*/
#ifndef __VIR_NET_SSH_SESSION_H__
# define __VIR_NET_SSH_SESSION_H__
# include "internal.h"
typedef struct _virNetSSHSession virNetSSHSession;
typedef virNetSSHSession *virNetSSHSessionPtr;
virNetSSHSessionPtr virNetSSHSessionNew(void);
void virNetSSHSessionFree(virNetSSHSessionPtr sess);
typedef enum {
VIR_NET_SSH_HOSTKEY_VERIFY_NORMAL,
VIR_NET_SSH_HOSTKEY_VERIFY_AUTO_ADD,
VIR_NET_SSH_HOSTKEY_VERIFY_IGNORE
} virNetSSHHostkeyVerify;
int virNetSSHSessionSetChannelCommand(virNetSSHSessionPtr sess,
const char *command);
void virNetSSHSessionAuthReset(virNetSSHSessionPtr sess);
int virNetSSHSessionAuthSetCallback(virNetSSHSessionPtr sess,
virConnectAuthPtr auth);
int virNetSSHSessionAuthAddPasswordAuth(virNetSSHSessionPtr sess,
const char *username,
const char *password);
int virNetSSHSessionAuthAddAgentAuth(virNetSSHSessionPtr sess,
const char *username);
int virNetSSHSessionAuthAddPrivKeyAuth(virNetSSHSessionPtr sess,
const char *username,
const char *keyfile,
const char *password);
int virNetSSHSessionAuthAddKeyboardAuth(virNetSSHSessionPtr sess,
const char *username,
int tries);
int virNetSSHSessionSetHostKeyVerification(virNetSSHSessionPtr sess,
const char *hostname,
int port,
const char *hostsfile,
bool readonly,
virNetSSHHostkeyVerify opt);
int virNetSSHSessionConnect(virNetSSHSessionPtr sess,
int sock);
ssize_t virNetSSHChannelRead(virNetSSHSessionPtr sess,
char *buf,
size_t len);
ssize_t virNetSSHChannelWrite(virNetSSHSessionPtr sess,
const char *buf,
size_t len);
bool virNetSSHSessionHasCachedData(virNetSSHSessionPtr sess);
#endif /* ___VIR_NET_SSH_SESSION_H_ */

View File

@ -113,7 +113,9 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST,
"Authentication Utils",
"DBus Utils",
"Parallels Cloud Server",
"Device Config"
"Device Config",
"SSH transport layer" /* 50 */
)
@ -1192,6 +1194,11 @@ virErrorMsg(virErrorNumber error, const char *info)
else
errmsg = _("Operation not supported: %s");
break;
case VIR_ERR_SSH:
if (info == NULL)
errmsg = _("SSH transport error");
else
errmsg = _("SSH transport error: %s");
}
return errmsg;
}