[libvirt] [PATCH] Add openauth example to demonstrate a custom auth callback

Matthias Bolte matthias.bolte at googlemail.com
Tue Jul 6 13:28:54 UTC 2010


---
 Makefile.am                   |    2 +-
 configure.ac                  |    1 +
 examples/openauth/.gitignore  |    5 +
 examples/openauth/Makefile.am |    5 +
 examples/openauth/openauth.c  |  287 +++++++++++++++++++++++++++++++++++++++++
 libvirt.spec.in               |    3 +-
 6 files changed, 301 insertions(+), 2 deletions(-)
 create mode 100644 examples/openauth/.gitignore
 create mode 100644 examples/openauth/Makefile.am
 create mode 100644 examples/openauth/openauth.c

diff --git a/Makefile.am b/Makefile.am
index 286b13b..a6af20f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,7 +6,7 @@ GENHTML = genhtml
 SUBDIRS = gnulib/lib include src daemon tools proxy docs gnulib/tests \
   python tests po examples/domain-events/events-c examples/hellolibvirt \
   examples/dominfo examples/domsuspend examples/python examples/apparmor \
-  examples/xml/nwfilter
+  examples/xml/nwfilter examples/openauth
 
 ACLOCAL_AMFLAGS = -I m4 -I gnulib/m4
 
diff --git a/configure.ac b/configure.ac
index c9c5b53..eece723 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2129,6 +2129,7 @@ AC_OUTPUT(Makefile src/Makefile include/Makefile docs/Makefile \
           examples/domain-events/events-c/Makefile \
           examples/domsuspend/Makefile \
           examples/dominfo/Makefile \
+          examples/openauth/Makefile \
           examples/python/Makefile \
           examples/hellolibvirt/Makefile \
           examples/xml/nwfilter/Makefile)
diff --git a/examples/openauth/.gitignore b/examples/openauth/.gitignore
new file mode 100644
index 0000000..1431557
--- /dev/null
+++ b/examples/openauth/.gitignore
@@ -0,0 +1,5 @@
+Makefile
+Makefile.in
+openauth
+.deps
+.libs
diff --git a/examples/openauth/Makefile.am b/examples/openauth/Makefile.am
new file mode 100644
index 0000000..279a032
--- /dev/null
+++ b/examples/openauth/Makefile.am
@@ -0,0 +1,5 @@
+INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include
+noinst_PROGRAMS = openauth
+openauth_CFLAGS = $(WARN_CFLAGS)
+openauth_SOURCES = openauth.c
+openauth_LDADD = @top_builddir@/src/libvirt.la
diff --git a/examples/openauth/openauth.c b/examples/openauth/openauth.c
new file mode 100644
index 0000000..ff830cb
--- /dev/null
+++ b/examples/openauth/openauth.c
@@ -0,0 +1,287 @@
+/* This is a copy of the hellolibvirt example demonstaring how to use
+ * virConnectOpenAuth with a custom auth callback */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libvirt/libvirt.h>
+#include <libvirt/virterror.h>
+
+static void
+showError(virConnectPtr conn)
+{
+    int ret;
+    virErrorPtr err;
+
+    err = malloc(sizeof(*err));
+    if (NULL == err) {
+        printf("Could not allocate memory for error data\n");
+        goto out;
+    }
+
+    ret = virConnCopyLastError(conn, err);
+
+    switch (ret) {
+    case 0:
+        printf("No error found\n");
+        break;
+
+    case -1:
+        printf("Parameter error when attempting to get last error\n");
+        break;
+
+    default:
+        printf("libvirt reported: \"%s\"\n", err->message);
+        break;
+    }
+
+    virResetError(err);
+    free(err);
+
+out:
+    return;
+}
+
+
+static int
+showHypervisorInfo(virConnectPtr conn)
+{
+    int ret = 0;
+    unsigned long hvVer, major, minor, release;
+    const char *hvType;
+
+    /* virConnectGetType returns a pointer to a static string, so no
+     * allocation or freeing is necessary; it is possible for the call
+     * to fail if, for example, there is no connection to a
+     * hypervisor, so check what it returns. */
+    hvType = virConnectGetType(conn);
+    if (NULL == hvType) {
+        ret = 1;
+        printf("Failed to get hypervisor type\n");
+        showError(conn);
+        goto out;
+    }
+
+    if (0 != virConnectGetVersion(conn, &hvVer)) {
+        ret = 1;
+        printf("Failed to get hypervisor version\n");
+        showError(conn);
+        goto out;
+    }
+
+    major = hvVer / 1000000;
+    hvVer %= 1000000;
+    minor = hvVer / 1000;
+    release = hvVer % 1000;
+
+    printf("Hypervisor: \"%s\" version: %lu.%lu.%lu\n",
+           hvType,
+           major,
+           minor,
+           release);
+
+out:
+    return ret;
+}
+
+
+static int
+showDomains(virConnectPtr conn)
+{
+    int ret = 0, i, numNames, numInactiveDomains, numActiveDomains;
+    char **nameList = NULL;
+
+    numActiveDomains = virConnectNumOfDomains(conn);
+    if (-1 == numActiveDomains) {
+        ret = 1;
+        printf("Failed to get number of active domains\n");
+        showError(conn);
+        goto out;
+    }
+
+    numInactiveDomains = virConnectNumOfDefinedDomains(conn);
+    if (-1 == numInactiveDomains) {
+        ret = 1;
+        printf("Failed to get number of inactive domains\n");
+        showError(conn);
+        goto out;
+    }
+
+    printf("There are %d active and %d inactive domains\n",
+           numActiveDomains, numInactiveDomains);
+
+    nameList = malloc(sizeof(*nameList) * numInactiveDomains);
+
+    if (NULL == nameList) {
+        ret = 1;
+        printf("Could not allocate memory for list of inactive domains\n");
+        goto out;
+    }
+
+    numNames = virConnectListDefinedDomains(conn,
+                                            nameList,
+                                            numInactiveDomains);
+
+    if (-1 == numNames) {
+        ret = 1;
+        printf("Could not get list of defined domains from hypervisor\n");
+        showError(conn);
+        goto out;
+    }
+
+    if (numNames > 0) {
+        printf("Inactive domains:\n");
+    }
+
+    for (i = 0 ; i < numNames ; i++) {
+        printf("  %s\n", *(nameList + i));
+        /* The API documentation doesn't say so, but the names
+         * returned by virConnectListDefinedDomains are strdup'd and
+         * must be freed here.  */
+        free(*(nameList + i));
+    }
+
+out:
+    free(nameList);
+    return ret;
+}
+
+/* Struct to pass the credentials to the auth callback via the cbdata pointer */
+struct _AuthData {
+    char *username;
+    char *password;
+};
+
+typedef struct _AuthData AuthData;
+
+/* This function will be called by libvirt to obtain credentials in order to
+ * authenticate to the hypervisor */
+static int
+authCallback(virConnectCredentialPtr cred, unsigned int ncred, void *cbdata)
+{
+    int i;
+    AuthData *authData = cbdata;
+
+    /* libvirt might request multiple credentials in a single call.
+     * This example supports VIR_CRED_AUTHNAME and VIR_CRED_PASSPHRASE
+     * credentials only, but there are several other types.
+     *
+     * A request may also contain a prompt message that can be displayed
+     * to the user and a challenge. The challenge is specific to the
+     * credential type and hypervisor type.
+     *
+     * For example the ESX driver passes the hostname of the ESX or vCenter
+     * server as challenge. This allows a auth callback to return the
+     * proper credentials. */
+    for (i = 0; i < ncred ; ++i) {
+        switch (cred[i].type) {
+        case VIR_CRED_AUTHNAME:
+            cred[i].result = strdup(authData->username);
+
+            if (cred[i].result == NULL) {
+                return -1;
+            }
+
+            cred[i].resultlen = strlen(cred[i].result);
+            break;
+
+        case VIR_CRED_PASSPHRASE:
+            cred[i].result = strdup(authData->password);
+
+            if (cred[i].result == NULL) {
+                return -1;
+            }
+
+            cred[i].resultlen = strlen(cred[i].result);
+            break;
+
+        default:
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+
+/* The list of credential types supported by our auth callback */
+static int credTypes[] = {
+    VIR_CRED_AUTHNAME,
+    VIR_CRED_PASSPHRASE
+};
+
+
+/* The auth struct that will be passed to virConnectOpenAuth */
+static virConnectAuth auth = {
+    credTypes,
+    sizeof(credTypes) / sizeof(int),
+    authCallback,
+    NULL, // cbdata will be initialized in main
+};
+
+
+int
+main(int argc, char *argv[])
+{
+    int ret = 0;
+    virConnectPtr conn;
+    char *uri;
+    AuthData authData;
+
+    if (argc != 4) {
+        ret = 1;
+        printf("Usage: %s <uri> <username> <password>\n", argv[0]);
+        goto out;
+    }
+
+    uri = argv[1];
+    authData.username = argv[2];
+    authData.password = argv[3];
+    auth.cbdata = &authData;
+
+    printf("Attempting to connect to hypervisor\n");
+
+    conn = virConnectOpenAuth(uri, &auth, 0);
+
+    if (NULL == conn) {
+        ret = 1;
+        printf("No connection to hypervisor\n");
+        showError(conn);
+        goto out;
+    }
+
+    uri = virConnectGetURI(conn);
+    if (NULL == uri) {
+        ret = 1;
+        printf("Failed to get URI for hypervisor connection\n");
+        showError(conn);
+        goto disconnect;
+    }
+
+    printf("Connected to hypervisor at \"%s\"\n", uri);
+    free(uri);
+
+    if (0 != showHypervisorInfo(conn)) {
+        ret = 1;
+        goto disconnect;
+    }
+
+    if (0 != showDomains(conn)) {
+        ret = 1;
+        goto disconnect;
+    }
+
+disconnect:
+    if (0 != virConnectClose(conn)) {
+        printf("Failed to disconnect from hypervisor\n");
+        showError(conn);
+        ret = 1;
+    } else {
+        printf("Disconnected from hypervisor\n");
+    }
+
+out:
+    return ret;
+}
diff --git a/libvirt.spec.in b/libvirt.spec.in
index 33e757c..ce58f2a 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -585,7 +585,7 @@ gzip -9 ChangeLog
 rm -fr %{buildroot}
 
 %makeinstall
-for i in domain-events/events-c dominfo domsuspend hellolibvirt python xml/nwfilter
+for i in domain-events/events-c dominfo domsuspend hellolibvirt openauth python xml/nwfilter
 do
   (cd examples/$i ; make clean ; rm -rf .deps .libs Makefile Makefile.in)
 done
@@ -887,6 +887,7 @@ fi
 %doc examples/domain-events/events-c
 %doc examples/dominfo
 %doc examples/domsuspend
+%doc examples/openauth
 %doc examples/xml
 
 %if %{with_python}
-- 
1.7.0.4




More information about the libvir-list mailing list