]> xenbits.xensource.com Git - libvirt.git/commitdiff
Lookup auth credentials in config file before prompting
authorDaniel P. Berrange <berrange@redhat.com>
Tue, 20 Mar 2012 11:11:10 +0000 (11:11 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Fri, 23 Mar 2012 13:24:07 +0000 (13:24 +0000)
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>
src/esx/esx_driver.c
src/hyperv/hyperv_driver.c
src/phyp/phyp_driver.c
src/remote/remote_driver.c
src/util/virauth.c
src/util/virauth.h
src/xenapi/xenapi_driver.c

index 7689306e82f6b4332db39610958892ada256accb..69628328d8e86cf58cbcd4f128e73b8415b912db 100644 (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;
         }
 
index 0469e2ee8d14fa96d5eb2babc6f38a55377494c5..05fce4f378129ff21203218a10446c1b0159dbc0 100644 (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"));
index 470706d9515a999455f3a20ed90d485a29bb825e..b883b5643433a3c49bd76916fbcbeb612b641be8 100644 (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",
index 1faaf9edbc76fadf08d928cefa8823e38efe1d5e..72b4b8fa37bd70060bcc0ef177d2ae723d05c140 100644 (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);
index 150b8e7a849bd257201f409b26af2ca55ea88b3b..940686f976712226652958ae60f8e64c8c8cb191 100644 (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));
 
index 7f43bee62a13de1f4a927395074f1fcb894c7eeb..1b315c720a1073886f42cf8079644c648810bffa 100644 (file)
 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__ */
index 3f88c915a5fc1a00174f8b3a5f6af9f6d6bdf56d..2967f7ca300e1ca8908b741241accbaaf0a806a3 100644 (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,