From 9af989fabc316f6e575b0763439a91e2899689fb Mon Sep 17 00:00:00 2001 From: Matthias Bolte Date: Tue, 6 Jul 2010 14:59:50 +0200 Subject: [PATCH] Add openauth example to demonstrate a custom auth callback --- 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 286b13b02f..a6af20f058 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 c9c5b53b16..eece723262 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 0000000000..1431557515 --- /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 0000000000..279a032ab7 --- /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 0000000000..4f01cdb0cc --- /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 + +#include +#include +#include +#include +#include + +static void +showError(virConnectPtr conn) +{ + int ret; + virErrorPtr err; + + err = malloc(sizeof(*err)); + if (err == NULL) { + 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 (hvType == NULL) { + ret = 1; + printf("Failed to get hypervisor type\n"); + showError(conn); + goto out; + } + + if (virConnectGetVersion(conn, &hvVer) != 0) { + 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 (numActiveDomains == -1) { + ret = 1; + printf("Failed to get number of active domains\n"); + showError(conn); + goto out; + } + + numInactiveDomains = virConnectNumOfDefinedDomains(conn); + if (numInactiveDomains == -1) { + 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 (nameList == NULL) { + ret = 1; + printf("Could not allocate memory for list of inactive domains\n"); + goto out; + } + + numNames = virConnectListDefinedDomains(conn, + nameList, + numInactiveDomains); + + if (numNames == -1) { + 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 \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 (uri == NULL) { + 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 (showHypervisorInfo(conn) != 0) { + ret = 1; + goto disconnect; + } + + if (showDomains(conn) != 0) { + ret = 1; + goto disconnect; + } + + disconnect: + if (virConnectClose(conn) != 0) { + 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 33e757c895..ce58f2a579 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}