The password authentication method wasn't used as there wasn't a pleasant way to pass the password. This patch adds the option to use virAuth util functions to request the password either from a config file or uses the conf callback to request it from the user. --- src/rpc/virnetsshsession.c | 80 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 16 deletions(-) diff --git a/src/rpc/virnetsshsession.c b/src/rpc/virnetsshsession.c index b6aedc8..113fc6b 100644 --- a/src/rpc/virnetsshsession.c +++ b/src/rpc/virnetsshsession.c @@ -36,6 +36,7 @@ #include "virfile.h" #include "virobject.h" #include "virstring.h" +#include "virauth.h" #define VIR_FROM_THIS VIR_FROM_SSH @@ -97,6 +98,7 @@ struct _virNetSSHSession { /* authentication stuff */ virConnectAuthPtr cred; + char *authPath; virNetSSHAuthCallbackError authCbErr; size_t nauths; virNetSSHAuthMethodPtr *auths; @@ -156,6 +158,7 @@ virNetSSHSessionDispose(void *obj) VIR_FREE(sess->channelCommand); VIR_FREE(sess->hostname); VIR_FREE(sess->knownHostsFile); + VIR_FREE(sess->authPath); } static virClassPtr virNetSSHSessionClass; @@ -675,7 +678,8 @@ virNetSSHAuthenticatePrivkey(virNetSSHSessionPtr sess, return 0; } -/* perform tunelled password authentication + +/* perform password authentication, either directly or request the password * * Returns: 0 on success * 1 on authentication failure @@ -685,27 +689,71 @@ static int virNetSSHAuthenticatePassword(virNetSSHSessionPtr sess, virNetSSHAuthMethodPtr priv) { + char *password = NULL; char *errmsg; - int ret; + int ret = -1; + int rc; + + if (priv->password) { + /* tunelled password authentication */ + if ((ret = libssh2_userauth_password(sess->session, + priv->username, + priv->password)) == 0) { + ret = 0; + goto cleanup; + } + } else { + /* password authentication with interactive password request */ + if (!sess->cred || !sess->cred->cb) { + virReportError(VIR_ERR_SSH, "%s", + _("Can't perform authentication: " + "Authentication callback not provided")); + goto cleanup; + } - /* tunelled password authentication */ - if ((ret = libssh2_userauth_password(sess->session, - priv->username, - priv->password)) < 0) { - libssh2_session_last_error(sess->session, &errmsg, NULL, 0); - virReportError(VIR_ERR_AUTH_FAILED, - _("tunelled password authentication failed: %s"), - errmsg); + /* Try the authenticating the set amount of times. The server breaks the + * connection if maximum number of bad auth tries is exceeded */ + while (true) { + if (!(password = virAuthGetPasswordPath(sess->authPath, sess->cred, + "ssh", priv->username, + sess->hostname))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to retrieve password")); + goto cleanup; + } - if (ret == LIBSSH2_ERROR_AUTHENTICATION_FAILED) - return 1; - else - return -1; + /* tunelled password authentication */ + if ((rc = libssh2_userauth_password(sess->session, + priv->username, + password)) == 0) { + ret = 0; + goto cleanup; + } + + if (ret != LIBSSH2_ERROR_AUTHENTICATION_FAILED) + break; + + VIR_FREE(password); + } } - /* auth success */ - return 0; + + /* error path */ + libssh2_session_last_error(sess->session, &errmsg, NULL, 0); + virReportError(VIR_ERR_AUTH_FAILED, + _("authentication failed: %s"), errmsg); + + /* determine exist status */ + if (ret == LIBSSH2_ERROR_AUTHENTICATION_FAILED) + return 1; + else + return -1; + +cleanup: + VIR_FREE(password); + return ret; } + /* perform keyboard interactive authentication * * Returns: 0 on success -- 1.8.2.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list