Lookup auth credentials in config file before prompting

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

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrange 2012-03-20 11:11:10 +00:00
parent c6c66615c2
commit 4445e16bfa
7 changed files with 224 additions and 63 deletions

View File

@ -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;
}

View File

@ -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"));

View File

@ -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",

View File

@ -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);

View File

@ -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));

View File

@ -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__ */

View File

@ -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,