[libvirt] [PATCH 2/5] libssh2_transport: add main libssh2 transport implementation

Eric Blake eblake at redhat.com
Mon Aug 6 20:46:56 UTC 2012


On 08/03/2012 08:03 AM, Peter Krempa wrote:
> This patch adds helper functions to libssh2 that enable us to use
> libssh2 in conjunction with libvirt-native virNetSockets instead of
> using a spawned "ssh" client process.
> 
> This implemetation supports tunneled plaintext, keyboard-interactive,

s/implemtation/implementation/

> 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, as 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 supported.
> 
> As a bonus, this should (untested) add SSH support to libvirt clients
> running on Windows.

>  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, [wether libssh2 transport is enabled])

s/wether/whether/

> +++ b/src/Makefile.am
> @@ -1508,6 +1508,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/virnetlibsshcontext.h rpc/virnetlibsshcontext.c
> +else
> +EXTRA_DIST += \
> +	rpc/virnetlibsshcontext.h rpc/virnetlibsshcontext.c
> +endif

Doing it this way requires a separate .syms file.  How hard would it be
to provide stub symbols, so that we always compile and link against the
file, but the file is a no-op when HAVE_LIBSSH2 is not available?

> +++ b/src/rpc/virnetlibsshcontext.c

> +/* keyboard interactive authentication callback */
> +static void
> +virNetLibSSHKbIntCb(const char *name ATTRIBUTE_UNUSED,
> +                    int name_len ATTRIBUTE_UNUSED,
> +                    const char *instruction ATTRIBUTE_UNUSED,
> +                    int instruction_len ATTRIBUTE_UNUSED,
> +                    int num_prompts,
> +                    const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
> +                    LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
> +                    void **opaque)
> +{

prompts is marked 'const', but...

> +    /* fill data structures for auth callback */
> +    for (i = 0; i < num_prompts; i++) {
> +        /* remove colon and trailing spaces from prompts, as default behavior
> +         * of libvirt's auth callback is to add them */
> +        if ((tmp = strrchr(prompts[i].text, ':')))
> +            *tmp = '\0';

...you are modifying it in-place by using strrchr to cast away const.
Is that an issue where you could cause a SEGV, and should be strdup'ing
the prompt before modifying it?


> +/* check session host keys
> + *
> + * this function checks the known host database and verifies the key
> + * errors are raised in this func
> + *
> + * return value: 0 on success, not 0 otherwise
> + */
> +static int
> +virNetLibSSHCheckHostKey(virNetLibSSHSessionPtr sess)

Is the return always negative on error?

> +            /* format the host key into a nice userfriendly string.
> +             * Sadly, there's no constant to describe the hash length, so
> +             * we have to use a *MAGIC* constant. */
> +            for (i = 0; i < 16; i++) {
> +                virBufferAsprintf(&buff, "%02X", (unsigned char) keyhash[i]);

Is the cast there to avoid unintentional sign-extension because
keyhash[i] might be signed?  If so, you could avoid the cast by telling
asprintf that you are passing 1 byte in the first place with the 'hh'
modifier.

> +                if (i != 15)
> +                    virBufferAddChar(&buff, ':');
> +            }

Slightly more efficient to use:

for (i = 0; i < 16; i++)
    virBufferAsprintf(&buff, "%02hhX:", keyhash[i]);
virBufferTrim(&buff, ":", 1);

> +
> +            if (STRNEQ_NULLABLE(askKey.result, _("yes"))) {
> +                virReportError(VIR_ERR_LIBSSH_ERROR,
> +                               _("SSH host key for '%s' (%s) was not accepted"),

When parsing user input, don't you want a case-insensitive comparison?
Also, what about users that want to type 'y' instead of 'yes'?  And is
comparing to a translated string wise?  Without consulting LC_MESSAGES
for the proper regex for the user's chosen locale, I'd almost feel safer
with a check hard-coded to English 'y' and 'n' rather than to the
arbitrary language _("yes").

I'm not quite sure how I would test all of the code, but the bulk of it
looked sane by just glancing over it.  Having not specifically coded
with libssh2, I can't say if you were using the library API correctly
without spending a lot longer on the review; but if it is possible to
easily test the results, that would go a long way to convince me that
the code itself is doing the right thing.

-- 
Eric Blake   eblake at redhat.com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 620 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20120806/61410f35/attachment-0001.sig>


More information about the libvir-list mailing list