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, -- 1.7.7.6 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list