[libvirt] [PATCH v3 3/6] libssh_transport: add new libssh-based transport

Pino Toscano ptoscano at redhat.com
Wed Nov 2 09:43:54 UTC 2016


On Tuesday, 1 November 2016 13:20:28 CET Peter Krempa wrote:
> On Wed, Oct 19, 2016 at 14:40:36 +0200, Pino Toscano wrote:
> > Implement a new libssh transport, which uses libssh to communicate with
> > remote hosts, and add all the build system stuff (search of libssh,
> > private symbols, etc) to built it.
> > 
> > This new transport supports all the common ssh authentication methods,
> > making use of libvirt's auth callbacks for interaction with the user.
> > ---
> >  config-post.h                 |    2 +
> >  configure.ac                  |    3 +
> >  m4/virt-libssh.m4             |   26 +
> >  po/POTFILES.in                |    1 +
> >  src/Makefile.am               |   21 +-
> >  src/libvirt_libssh.syms       |   22 +
> >  src/rpc/virnetlibsshsession.c | 1458 +++++++++++++++++++++++++++++++++++++++++
> >  src/rpc/virnetlibsshsession.h |   80 +++
> >  8 files changed, 1611 insertions(+), 2 deletions(-)
> >  create mode 100644 m4/virt-libssh.m4
> >  create mode 100644 src/libvirt_libssh.syms
> >  create mode 100644 src/rpc/virnetlibsshsession.c
> >  create mode 100644 src/rpc/virnetlibsshsession.h
> 
> 
> > diff --git a/src/rpc/virnetlibsshsession.c b/src/rpc/virnetlibsshsession.c
> > new file mode 100644
> > index 0000000..13dd52c
> > --- /dev/null
> > +++ b/src/rpc/virnetlibsshsession.c
> > @@ -0,0 +1,1458 @@
> 
> [...]
> 
> > +static void
> > +virNetLibsshSessionAuthMethodsFree(virNetLibsshSessionPtr sess)
> > +{
> > +    size_t i;
> > +
> > +    for (i = 0; i < sess->nauths; i++) {
> > +        VIR_FREE(sess->auths[i]->password);
> 
> This should be turned into VIR_DISPOSE_STR.

Right. (Note the same fix should be done in the libssh2 transport too.)

> > +
> > +/* string representation of public key of remote server */
> > +static char *
> > +virSshServerKeyAsString(virNetLibsshSessionPtr sess)
> > +{
> > +    int ret;
> > +    ssh_key key;
> > +    unsigned char *keyhash;
> > +    size_t keyhashlen;
> > +    char *str;
> > +
> > +    if (ssh_get_publickey(sess->session, &key) != SSH_OK) {
> > +        virReportError(VIR_ERR_LIBSSH, "%s",
> > +                       _("failed to get the key of the current "
> > +                         "session"));
> > +        return NULL;
> > +    }
> > +
> > +    /* calculate remote key hash, using MD5 algorithm that is
> > +     * usual in OpenSSH. The returned value must be freed */
> > +    ret = ssh_get_publickey_hash(key, SSH_PUBLICKEY_HASH_MD5,
> > +                                 &keyhash, &keyhashlen);
> 
> Openssh currently is using SHA256 with base64 encoding. I think we
> should at least for libssh switch to this newer approach.

Unfortunately the libssh API only allows SHA1 and MD5:

enum ssh_publickey_hash_type {
    SSH_PUBLICKEY_HASH_SHA1,
    SSH_PUBLICKEY_HASH_MD5
};

libssh2 uses MD5, which is why I chose to do the same in this case.
I will change it to SHA1, should be slightly better.

> > +void
> > +virNetLibsshSessionAuthReset(virNetLibsshSessionPtr sess)
> 
> This function is not used anywhere in this series.

Neither is virNetSSHSessionAuthReset -- removed.

> > +/* perform keyboard interactive authentication
> > + *
> > + * returns SSH_AUTH_* values
> > + */
> > +static int
> > +virNetLibsshAuthenticateKeyboardInteractive(virNetLibsshSessionPtr sess,
> > +                                            virNetLibsshAuthMethodPtr priv)
> > +{
> > +    int ret;
> > +    const char *errmsg;
> > +    int try = 0;
> > +
> > +    /* request user's key password */
> > +    if (!sess->cred || !sess->cred->cb) {
> > +        virReportError(VIR_ERR_LIBSSH, "%s",
> > +                       _("No user interaction callback provided: "
> > +                         "Can't get input from keyboard interactive "
> > +                         "authentication"));
> > +        return SSH_AUTH_ERROR;
> > +    }
> > +
> > + again:
> 
> Please use a while loop for this purpose.
> 
> > +    ret = ssh_userauth_kbdint(sess->session, NULL, NULL);
> > +    while (ret == SSH_AUTH_INFO) {
> > +        const char *name, *instruction;
> > +        int nprompts, iprompt;
> > +        virBuffer buff = VIR_BUFFER_INITIALIZER;
> > +
> > +        name = ssh_userauth_kbdint_getname(sess->session);
> > +        instruction = ssh_userauth_kbdint_getinstruction(sess->session);
> > +        nprompts = ssh_userauth_kbdint_getnprompts(sess->session);
> > +
> > +        /* compose the main buffer with name and instruction, if present */
> > +        if (name && name[0])
> > +            virBufferAddStr(&buff, name);
> > +        if (instruction && instruction[0]) {
> > +            if (virBufferUse(&buff) > 0)
> > +                virBufferAddChar(&buff, '\n');
> > +            virBufferAddStr(&buff, instruction);
> > +        }
> > +
> > +        if (virBufferCheckError(&buff) < 0)
> > +            return -1;
> > +
> > +        for (iprompt = 0; iprompt < nprompts; ++iprompt) {
> > +            virConnectCredential retr_passphrase;
> > +            const char *promptStr;
> > +            char echo;
> > +            virBuffer prompt_buff = VIR_BUFFER_INITIALIZER;
> > +            char *prompt = NULL;
> > +            int cred_type;
> > +
> > +            /* get the prompt, stripping the trailing newlines and spaces */
> > +            promptStr = ssh_userauth_kbdint_getprompt(sess->session, iprompt,
> > +                                                      &echo);
> > +
> > +            cred_type = virCredTypeForPrompt(sess->cred, echo);
> > +            if (cred_type == -1) {
> > +                virReportError(VIR_ERR_LIBSSH, "%s",
> > +                               _("no suitable callback for input of keyboard "
> > +                                 "response"));
> > +                goto prompt_error;
> > +            }
> > +
> > +            /* compose the instruction buffer with this prompt */
> > +            if (virBufferUse(&buff) > 0) {
> > +                virBufferAddBuffer(&prompt_buff, &buff);
> > +                virBufferAddChar(&prompt_buff, '\n');
> > +            }
> > +            virBufferAdd(&prompt_buff, promptStr,
> > +                         virLengthForPromptString(promptStr));
> > +
> > +            if (virBufferCheckError(&prompt_buff) < 0)
> > +                goto prompt_error;
> > +
> > +            prompt = virBufferContentAndReset(&prompt_buff);
> > +
> > +            memset(&retr_passphrase, 0, sizeof(virConnectCredential));
> > +            retr_passphrase.type = cred_type;
> > +            retr_passphrase.prompt = prompt;
> > +
> > +            if (retr_passphrase.type == -1) {
> > +                virReportError(VIR_ERR_LIBSSH, "%s",
> > +                               _("no suitable callback for input of key "
> > +                                 "passphrase"));
> > +                goto prompt_error;
> > +            }
> > +
> > +            if (sess->cred->cb(&retr_passphrase, 1, sess->cred->cbdata)) {
> > +                virReportError(VIR_ERR_LIBSSH, "%s",
> > +                               _("failed to retrieve keyboard interactive "
> > +                                 "result: callback has failed"));
> > +                goto prompt_error;
> > +            }
> > +
> > +            VIR_FREE(prompt);
> > +
> > +            ret = ssh_userauth_kbdint_setanswer(sess->session, iprompt,
> > +                                                retr_passphrase.result);
> > +            VIR_DISPOSE_STRING(retr_passphrase.result);
> > +            if (ret < 0) {
> > +                errmsg = ssh_get_error(sess->session);
> > +                virReportError(VIR_ERR_AUTH_FAILED,
> > +                               _("authentication failed: %s"), errmsg);
> > +                goto prompt_error;
> > +            }
> 
> Maybe it would be better to extract this into a function since this
> looks rather complex.

How "granular" should this be split?

Thanks,
-- 
Pino Toscano
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part.
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20161102/c601fd49/attachment-0001.sig>


More information about the libvir-list mailing list