[libvirt] [PATCH 14/14] Lookup auth credentials in config file before prompting

Daniel P. Berrange berrange at redhat.com
Tue Mar 20 17:33:38 UTC 2012


From: "Daniel P. Berrange" <berrange at redhat.com>

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




More information about the libvir-list mailing list