From: "Daniel P. Berrange"<berrange@xxxxxxxxxx>
When SASL requests auth credentials, try to look them up in the
config file first. If any are found, remove them from the list
that the user is prompted for
---
src/esx/esx_driver.c | 58 +++++++++---------
src/hyperv/hyperv_driver.c | 4 +-
src/phyp/phyp_driver.c | 4 +-
src/remote/remote_driver.c | 138 ++++++++++++++++++++++++++++++++++++--------
src/util/virauth.c | 69 +++++++++++++++++++++-
src/util/virauth.h | 10 +++-
src/xenapi/xenapi_driver.c | 4 +-
7 files changed, 224 insertions(+), 63 deletions(-)
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
index 7689306..6962832 100644
--- a/src/esx/esx_driver.c
+++ b/src/esx/esx_driver.c
@@ -667,10 +667,8 @@ esxCapsInit(esxPrivate *priv)
static int
-esxConnectToHost(esxPrivate *priv, virConnectAuthPtr auth,
- const char *hostname, int port,
- const char *predefinedUsername,
- esxVI_ProductVersion expectedProductVersion,
+esxConnectToHost(virConnectPtr conn,
+ virConnectAuthPtr auth,
char **vCenterIpAddress)
{
int result = -1;
@@ -682,25 +680,29 @@ esxConnectToHost(esxPrivate *priv, virConnectAuthPtr auth,
esxVI_String *propertyNameList = NULL;
esxVI_ObjectContent *hostSystem = NULL;
esxVI_Boolean inMaintenanceMode = esxVI_Boolean_Undefined;
+ esxPrivate *priv = conn->privateData;
+ esxVI_ProductVersion expectedProductVersion = STRCASEEQ(conn->uri->scheme, "esx")
+ ? esxVI_ProductVersion_ESX
+ : esxVI_ProductVersion_GSX;
if (vCenterIpAddress == NULL || *vCenterIpAddress != NULL) {
ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
return -1;
}
- if (esxUtil_ResolveHostname(hostname, ipAddress, NI_MAXHOST)< 0) {
+ if (esxUtil_ResolveHostname(conn->uri->server, ipAddress, NI_MAXHOST)< 0) {
return -1;
}
- if (predefinedUsername != NULL) {
- username = strdup(predefinedUsername);
+ if (conn->uri->user != NULL) {
+ username = strdup(conn->uri->user);
if (username == NULL) {
virReportOOMError();
goto cleanup;
}
} else {
- username = virAuthGetUsername(auth, "root", hostname);
+ username = virAuthGetUsername(conn, auth, "esx", "root", conn->uri->server);
if (username == NULL) {
ESX_ERROR(VIR_ERR_AUTH_FAILED, "%s", _("Username request failed"));
@@ -708,7 +710,7 @@ esxConnectToHost(esxPrivate *priv, virConnectAuthPtr auth,
}
}
- unescapedPassword = virAuthGetPassword(auth, username, hostname);
+ unescapedPassword = virAuthGetPassword(conn, auth, "esx", username, conn->uri->server);
if (unescapedPassword == NULL) {
ESX_ERROR(VIR_ERR_AUTH_FAILED, "%s", _("Password request failed"));
@@ -722,7 +724,7 @@ esxConnectToHost(esxPrivate *priv, virConnectAuthPtr auth,
}
if (virAsprintf(&url, "%s://%s:%d/sdk", priv->parsedUri->transport,
- hostname, port)< 0) {
+ conn->uri->server, conn->uri->port)< 0) {
virReportOOMError();
goto cleanup;
}
@@ -743,13 +745,13 @@ esxConnectToHost(esxPrivate *priv, virConnectAuthPtr auth,
priv->host->productVersion != esxVI_ProductVersion_ESX5x) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("%s is neither an ESX 3.5, 4.x nor 5.x host"),
- hostname);
+ conn->uri->server);
goto cleanup;
}
} else { /* GSX */
if (priv->host->productVersion != esxVI_ProductVersion_GSX20) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
- _("%s isn't a GSX 2.0 host"), hostname);
+ _("%s isn't a GSX 2.0 host"), conn->uri->server);
goto cleanup;
}
}
@@ -799,9 +801,9 @@ esxConnectToHost(esxPrivate *priv, virConnectAuthPtr auth,
static int
-esxConnectToVCenter(esxPrivate *priv, virConnectAuthPtr auth,
- const char *hostname, int port,
- const char *predefinedUsername,
+esxConnectToVCenter(virConnectPtr conn,
+ virConnectAuthPtr auth,
+ const char *hostname,
const char *hostSystemIpAddress)
{
int result = -1;
@@ -810,6 +812,7 @@ esxConnectToVCenter(esxPrivate *priv, virConnectAuthPtr auth,
char *unescapedPassword = NULL;
char *password = NULL;
char *url = NULL;
+ esxPrivate *priv = conn->privateData;
if (hostSystemIpAddress == NULL&&
(priv->parsedUri->path == NULL || STREQ(priv->parsedUri->path, "/"))) {
@@ -822,15 +825,15 @@ esxConnectToVCenter(esxPrivate *priv, virConnectAuthPtr auth,
return -1;
}
- if (predefinedUsername != NULL) {
- username = strdup(predefinedUsername);
+ if (conn->uri->user != NULL) {
+ username = strdup(conn->uri->user);
if (username == NULL) {
virReportOOMError();
goto cleanup;
}
} else {
- username = virAuthGetUsername(auth, "administrator", hostname);
+ username = virAuthGetUsername(conn, auth, "esx", "administrator", hostname);
if (username == NULL) {
ESX_ERROR(VIR_ERR_AUTH_FAILED, "%s", _("Username request failed"));
@@ -838,7 +841,7 @@ esxConnectToVCenter(esxPrivate *priv, virConnectAuthPtr auth,
}
}
- unescapedPassword = virAuthGetPassword(auth, username, hostname);
+ unescapedPassword = virAuthGetPassword(conn, auth, "esx", username, hostname);
if (unescapedPassword == NULL) {
ESX_ERROR(VIR_ERR_AUTH_FAILED, "%s", _("Password request failed"));
@@ -852,7 +855,7 @@ esxConnectToVCenter(esxPrivate *priv, virConnectAuthPtr auth,
}
if (virAsprintf(&url, "%s://%s:%d/sdk", priv->parsedUri->transport,
- hostname, port)< 0) {
+ hostname, conn->uri->port)< 0) {
virReportOOMError();
goto cleanup;
}
@@ -1046,11 +1049,7 @@ esxOpen(virConnectPtr conn, virConnectAuthPtr auth,
if (STRCASEEQ(conn->uri->scheme, "esx") ||
STRCASEEQ(conn->uri->scheme, "gsx")) {
/* Connect to host */
- if (esxConnectToHost(priv, auth, conn->uri->server, conn->uri->port,
- conn->uri->user,
- STRCASEEQ(conn->uri->scheme, "esx")
- ? esxVI_ProductVersion_ESX
- : esxVI_ProductVersion_GSX,
+ if (esxConnectToHost(conn, auth,
&potentialVCenterIpAddress)< 0) {
goto cleanup;
}
@@ -1089,8 +1088,8 @@ esxOpen(virConnectPtr conn, virConnectAuthPtr auth,
}
}
- if (esxConnectToVCenter(priv, auth, vCenterIpAddress,
- conn->uri->port, NULL,
+ if (esxConnectToVCenter(conn, auth,
+ vCenterIpAddress,
priv->host->ipAddress)< 0) {
goto cleanup;
}
@@ -1099,8 +1098,9 @@ esxOpen(virConnectPtr conn, virConnectAuthPtr auth,
priv->primary = priv->host;
} else { /* VPX */
/* Connect to vCenter */
- if (esxConnectToVCenter(priv, auth, conn->uri->server, conn->uri->port,
- conn->uri->user, NULL)< 0) {
+ if (esxConnectToVCenter(conn, auth,
+ conn->uri->server,
+ NULL)< 0) {
goto cleanup;
}
diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c
index 0469e2e..05fce4f 100644
--- a/src/hyperv/hyperv_driver.c
+++ b/src/hyperv/hyperv_driver.c
@@ -147,7 +147,7 @@ hypervOpen(virConnectPtr conn, virConnectAuthPtr auth, unsigned int flags)
goto cleanup;
}
} else {
- username = virAuthGetUsername(auth, "administrator", conn->uri->server);
+ username = virAuthGetUsername(conn, auth, "hyperv", "administrator", conn->uri->server);
if (username == NULL) {
HYPERV_ERROR(VIR_ERR_AUTH_FAILED, "%s", _("Username request failed"));
@@ -155,7 +155,7 @@ hypervOpen(virConnectPtr conn, virConnectAuthPtr auth, unsigned int flags)
}
}
- password = virAuthGetPassword(auth, username, conn->uri->server);
+ password = virAuthGetPassword(conn, auth, "hyperv", username, conn->uri->server);
if (password == NULL) {
HYPERV_ERROR(VIR_ERR_AUTH_FAILED, "%s", _("Password request failed"));
diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c
index 470706d..b883b56 100644
--- a/src/phyp/phyp_driver.c
+++ b/src/phyp/phyp_driver.c
@@ -1006,7 +1006,7 @@ openSSHSession(virConnectPtr conn, virConnectAuthPtr auth,
goto err;
}
- username = virAuthGetUsername(auth, NULL, conn->uri->server);
+ username = virAuthGetUsername(conn, auth, "ssh", NULL, conn->uri->server);
if (username == NULL) {
PHYP_ERROR(VIR_ERR_AUTH_FAILED, "%s",
@@ -1087,7 +1087,7 @@ keyboard_interactive:
goto disconnect;
}
- password = virAuthGetPassword(auth, username, conn->uri->server);
+ password = virAuthGetPassword(conn, auth, "ssh", username, conn->uri->server);
if (password == NULL) {
PHYP_ERROR(VIR_ERR_AUTH_FAILED, "%s",
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 1faaf9e..72b4b8f 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -45,6 +45,8 @@
#include "intprops.h"
#include "virtypedparam.h"
#include "viruri.h"
+#include "virauth.h"
+#include "virauthconfig.h"
#define VIR_FROM_THIS VIR_FROM_REMOTE
@@ -461,6 +463,9 @@ doRemoteOpen (virConnectPtr conn,
pkipath = strdup(var->value);
if (!pkipath) goto out_of_memory;
var->ignore = 1;
+ } else if (STRCASEEQ(var->name, "authfile")) {
+ /* Strip this param, used by virauth.c */
+ var->ignore = 1;
} else {
VIR_DEBUG("passing through variable '%s' ('%s') to remote end",
var->name, var->value);
@@ -2870,27 +2875,35 @@ static int remoteAuthMakeCredentials(sasl_interact_t *interact,
if (!cred)
return -1;
- for (ninteract = 0 ; interact[ninteract].id != 0 ; ninteract++)
- ; /* empty */
+ for (ninteract = 0, *ncred = 0 ; interact[ninteract].id != 0 ; ninteract++) {
+ if (interact[ninteract].result)
+ continue;
+ (*ncred)++;
+ }
- if (VIR_ALLOC_N(*cred, ninteract)< 0)
+ if (VIR_ALLOC_N(*cred, *ncred)< 0)
return -1;
- for (ninteract = 0 ; interact[ninteract].id != 0 ; ninteract++) {
- (*cred)[ninteract].type = remoteAuthCredSASL2Vir(interact[ninteract].id);
- if (!(*cred)[ninteract].type) {
+ for (ninteract = 0, *ncred = 0 ; interact[ninteract].id != 0 ; ninteract++) {
+ if (interact[ninteract].result)
+ continue;
+
+ (*cred)[*ncred].type = remoteAuthCredSASL2Vir(interact[ninteract].id);
+ if (!(*cred)[*ncred].type) {
+ *ncred = 0;
VIR_FREE(*cred);
return -1;
}
- if (interact[ninteract].challenge)
- (*cred)[ninteract].challenge = interact[ninteract].challenge;
- (*cred)[ninteract].prompt = interact[ninteract].prompt;
- if (interact[ninteract].defresult)
- (*cred)[ninteract].defresult = interact[ninteract].defresult;
- (*cred)[ninteract].result = NULL;
+ if (interact[*ncred].challenge)
+ (*cred)[*ncred].challenge = interact[ninteract].challenge;
+ (*cred)[*ncred].prompt = interact[ninteract].prompt;
+ if (interact[*ncred].defresult)
+ (*cred)[*ncred].defresult = interact[ninteract].defresult;
+ (*cred)[*ncred].result = NULL;
+
+ (*ncred)++;
}
- *ncred = ninteract;
return 0;
}
@@ -2905,22 +2918,91 @@ static int remoteAuthMakeCredentials(sasl_interact_t *interact,
static void remoteAuthFillInteract(virConnectCredentialPtr cred,
sasl_interact_t *interact)
{
- int ninteract;
- for (ninteract = 0 ; interact[ninteract].id != 0 ; ninteract++) {
- interact[ninteract].result = cred[ninteract].result;
- interact[ninteract].len = cred[ninteract].resultlen;
+ int ninteract, ncred;
+ for (ninteract = 0, ncred = 0 ; interact[ninteract].id != 0 ; ninteract++) {
+ if (interact[ninteract].result)
+ continue;
+ interact[ninteract].result = cred[ncred].result;
+ interact[ninteract].len = cred[ncred].resultlen;
+ ncred++;
}
}
-
struct remoteAuthInteractState {
sasl_interact_t *interact;
virConnectCredentialPtr cred;
size_t ncred;
+ virAuthConfigPtr config;
};
-static void remoteAuthInteractStateClear(struct remoteAuthInteractState *state)
+
+static int remoteAuthFillFromConfig(virConnectPtr conn,
+ struct remoteAuthInteractState *state)
+{
+ int ret = -1;
+ int ninteract;
+ const char *credname;
+ char *path = NULL;
+
+ VIR_DEBUG("Trying to fill auth parameters from config file");
+
+ if (!state->config) {
+ if (virAuthGetConfigFilePath(conn,&path)< 0)
+ goto cleanup;
+ if (path == NULL) {
+ ret = 0;
+ goto cleanup;
+ }
+
+ if (!(state->config = virAuthConfigNew(path)))
+ goto cleanup;
+ }
+
+ for (ninteract = 0 ; state->interact[ninteract].id != 0 ; ninteract++) {
+ const char *value = NULL;
+
+ switch (state->interact[ninteract].id) {
+ case SASL_CB_USER:
+ credname = "username";
+ break;
+ case SASL_CB_AUTHNAME:
+ credname = "authname";
+ break;
+ case SASL_CB_PASS:
+ credname = "password";
+ break;
+ case SASL_CB_GETREALM:
+ credname = "realm";
+ break;
+ default:
+ credname = NULL;
+ break;
+ }
+
+ if (virAuthConfigLookup(state->config,
+ "libvirt",
+ conn->uri->server,
+ credname,
+&value)< 0)
+ goto cleanup;
+
+ if (value) {
+ state->interact[ninteract].result = value;
+ state->interact[ninteract].len = strlen(value);
+ }
+ }
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(path);
+ return ret;
+}
+
+
+static void remoteAuthInteractStateClear(struct remoteAuthInteractState *state,
+ bool final)
{
size_t i;
if (!state)
@@ -2930,15 +3012,23 @@ static void remoteAuthInteractStateClear(struct remoteAuthInteractState *state)
VIR_FREE(state->cred[i].result);
VIR_FREE(state->cred);
state->ncred = 0;
+
+ if (final)
+ virAuthConfigFree(state->config);
}
-static int remoteAuthInteract(struct remoteAuthInteractState *state,
+static int remoteAuthInteract(virConnectPtr conn,
+ struct remoteAuthInteractState *state,
virConnectAuthPtr auth)
{
int ret = -1;
- remoteAuthInteractStateClear(state);
+ VIR_DEBUG("Starting SASL interaction");
+ remoteAuthInteractStateClear(state, false);
+
+ if (remoteAuthFillFromConfig(conn, state)< 0)
+ goto cleanup;
if (remoteAuthMakeCredentials(state->interact,&state->cred,&state->ncred)< 0) {
remoteError(VIR_ERR_AUTH_FAILED, "%s",
@@ -3074,7 +3164,7 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv,
/* Need to gather some credentials from the client */
if (err == VIR_NET_SASL_INTERACT) {
- if (remoteAuthInteract(&state, auth)< 0) {
+ if (remoteAuthInteract(conn,&state, auth)< 0) {
VIR_FREE(iret.mechlist);
goto cleanup;
}
@@ -3126,7 +3216,7 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv,
/* Need to gather some credentials from the client */
if (err == VIR_NET_SASL_INTERACT) {
- if (remoteAuthInteract(&state, auth)< 0) {
+ if (remoteAuthInteract(conn,&state, auth)< 0) {
VIR_FREE(iret.mechlist);
goto cleanup;
}
@@ -3192,7 +3282,7 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv,
cleanup:
VIR_FREE(serverin);
- remoteAuthInteractStateClear(&state);
+ remoteAuthInteractStateClear(&state, true);
VIR_FREE(saslcb);
virNetSASLSessionFree(sasl);
virNetSASLContextFree(saslCtxt);
diff --git a/src/util/virauth.c b/src/util/virauth.c
index 150b8e7..940686f 100644
--- a/src/util/virauth.c
+++ b/src/util/virauth.c
@@ -30,6 +30,7 @@
#include "datatypes.h"
#include "virterror_internal.h"
#include "configmake.h"
+#include "virauthconfig.h"
#define VIR_FROM_THIS VIR_FROM_AUTH
@@ -100,13 +101,68 @@ no_memory:
}
+static int
+virAuthGetCredential(virConnectPtr conn,
+ const char *servicename,
+ const char *credname,
+ char **value)
+{
+ int ret = -1;
+ char *path = NULL;
+ virAuthConfigPtr config = NULL;
+ const char *tmp;
+
+ *value = NULL;
+
+ if (virAuthGetConfigFilePath(conn,&path)< 0)
+ goto cleanup;
+
+ if (path == NULL) {
+ ret = 0;
+ goto cleanup;
+ }
+
+ if (!(config = virAuthConfigNew(path)))
+ goto cleanup;
+
+ if (virAuthConfigLookup(config,
+ servicename,
+ conn->uri->server,
+ credname,
+&tmp)< 0)
+ goto cleanup;
+
+ if (tmp&&
+ !(*value = strdup(tmp))) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ virAuthConfigFree(config);
+ VIR_FREE(path);
+ return ret;
+}
+
+
char *
-virAuthGetUsername(virConnectAuthPtr auth, const char *defaultUsername,
+virAuthGetUsername(virConnectPtr conn,
+ virConnectAuthPtr auth,
+ const char *servicename,
+ const char *defaultUsername,
const char *hostname)
{
unsigned int ncred;
virConnectCredential cred;
char *prompt;
+ char *ret = NULL;
+
+ if (virAuthGetCredential(conn, servicename, "username",&ret)< 0)
+ return NULL;
+ if (ret != NULL)
+ return ret;
memset(&cred, 0, sizeof (virConnectCredential));
@@ -148,12 +204,21 @@ virAuthGetUsername(virConnectAuthPtr auth, const char *defaultUsername,
char *
-virAuthGetPassword(virConnectAuthPtr auth, const char *username,
+virAuthGetPassword(virConnectPtr conn,
+ virConnectAuthPtr auth,
+ const char *servicename,
+ const char *username,
const char *hostname)
{
unsigned int ncred;
virConnectCredential cred;
char *prompt;
+ char *ret = NULL;
+
+ if (virAuthGetCredential(conn, servicename, "password",&ret)< 0)
+ return NULL;
+ if (ret != NULL)
+ return ret;
memset(&cred, 0, sizeof (virConnectCredential));
diff --git a/src/util/virauth.h b/src/util/virauth.h
index 7f43bee..1b315c7 100644
--- a/src/util/virauth.h
+++ b/src/util/virauth.h
@@ -27,9 +27,15 @@
int virAuthGetConfigFilePath(virConnectPtr conn,
char **path);
-char *virAuthGetUsername(virConnectAuthPtr auth, const char *defaultUsername,
+char *virAuthGetUsername(virConnectPtr conn,
+ virConnectAuthPtr auth,
+ const char *servicename,
+ const char *defaultUsername,
const char *hostname);
-char *virAuthGetPassword(virConnectAuthPtr auth, const char *username,
+char *virAuthGetPassword(virConnectPtr conn,
+ virConnectAuthPtr auth,
+ const char *servicename,
+ const char *username,
const char *hostname);
#endif /* __VIR_AUTH_H__ */
diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c
index 3f88c91..2967f7c 100644
--- a/src/xenapi/xenapi_driver.c
+++ b/src/xenapi/xenapi_driver.c
@@ -138,7 +138,7 @@ xenapiOpen (virConnectPtr conn, virConnectAuthPtr auth,
goto error;
}
} else {
- username = virAuthGetUsername(auth, NULL, conn->uri->server);
+ username = virAuthGetUsername(conn, auth, "xen", NULL, conn->uri->server);
if (username == NULL) {
xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED,
@@ -147,7 +147,7 @@ xenapiOpen (virConnectPtr conn, virConnectAuthPtr auth,
}
}
- password = virAuthGetPassword(auth, username, conn->uri->server);
+ password = virAuthGetPassword(conn, auth, "xen", username, conn->uri->server);
if (password == NULL) {
xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED,