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