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

Daniel Veillard veillard at redhat.com
Tue Jul 6 13:50:37 UTC 2010


On Tue, Jul 06, 2010 at 03:28:54PM +0200, Matthias Bolte wrote:
> ---
>  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}

  Looks fine to me, good idea :-)

ACK

Daniel

-- 
Daniel Veillard      | libxml Gnome XML XSLT toolkit  http://xmlsoft.org/
daniel at veillard.com  | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library  http://libvirt.org/




More information about the libvir-list mailing list