From 4445e16bfa8056980ac643fabf17186f9e685925 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 20 Mar 2012 11:11:10 +0000 Subject: [PATCH] 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 --- 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 7689306e82..69628328d8 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 0469e2ee8d..05fce4f378 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 470706d951..b883b56434 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 1faaf9edbc..72b4b8fa37 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 150b8e7a84..940686f976 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 7f43bee62a..1b315c720a 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 3f88c915a5..2967f7ca30 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, -- 2.39.5