From 873db60c0e52893a38c374d867d0a305e5419d6a Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Wed, 8 Jan 2014 19:36:00 +0000 Subject: [PATCH] tests: Add a regression test of libvirt authentication events. This requires a change to libvirt (in libvirt >= 1.2.1), see: https://www.redhat.com/archives/libvir-list/2014-January/msg00378.html --- .gitignore | 1 + tests/events/Makefile.am | 32 +++- tests/events/libvirt-auth.xml | 22 +++ tests/events/test-libvirt-auth-callbacks.c | 185 +++++++++++++++++++++ 4 files changed, 235 insertions(+), 5 deletions(-) create mode 100644 tests/events/libvirt-auth.xml create mode 100644 tests/events/test-libvirt-auth-callbacks.c diff --git a/.gitignore b/.gitignore index d22086798..45d3a7df1 100644 --- a/.gitignore +++ b/.gitignore @@ -467,6 +467,7 @@ Makefile.in /tests/data/initrd-x86_64.img.gz /tests/data/test-grep.txt.gz /tests/data/test.iso +/tests/events/test-libvirt-auth-callbacks /tests/guests/blank-*.img /tests/guests/debian.img /tests/guests/fedora.img diff --git a/tests/events/Makefile.am b/tests/events/Makefile.am index 9f6e5aa15..9751edc8d 100644 --- a/tests/events/Makefile.am +++ b/tests/events/Makefile.am @@ -1,5 +1,5 @@ # libguestfs -# Copyright (C) 2013 Red Hat Inc. +# Copyright (C) 2013-2014 Red Hat Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -17,10 +17,32 @@ include $(top_srcdir)/subdir-rules.mk -TESTS = \ - test-console-debug.pl +EXTRA_DIST = \ + test-console-debug.pl \ + libvirt-auth.xml TESTS_ENVIRONMENT = $(top_builddir)/run --test -EXTRA_DIST = \ - $(TESTS) +check_PROGRAMS = + +TESTS = test-console-debug.pl + +if HAVE_LIBVIRT +TESTS += test-libvirt-auth-callbacks +check_PROGRAMS += test-libvirt-auth-callbacks + +test_libvirt_auth_callbacks_SOURCES = test-libvirt-auth-callbacks.c +test_libvirt_auth_callbacks_CPPFLAGS = \ + -I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \ + -I$(top_srcdir)/src -I$(top_builddir)/src +test_libvirt_auth_callbacks_CFLAGS = \ + $(WARN_CFLAGS) $(WERROR_CFLAGS) \ + $(GPROF_CFLAGS) $(GCOV_CFLAGS) \ + $(LIBVIRT_CFLAGS) +test_libvirt_auth_callbacks_LDADD = \ + $(top_builddir)/src/libutils.la \ + $(top_builddir)/src/libguestfs.la \ + $(LIBVIRT_LIBS) \ + $(LIBXML2_LIBS) \ + $(top_builddir)/gnulib/lib/libgnu.la +endif diff --git a/tests/events/libvirt-auth.xml b/tests/events/libvirt-auth.xml new file mode 100644 index 000000000..d138d4d57 --- /dev/null +++ b/tests/events/libvirt-auth.xml @@ -0,0 +1,22 @@ + + + test + 1048576 + + hvm + + + + + + + + + + + + + rich + jane + + diff --git a/tests/events/test-libvirt-auth-callbacks.c b/tests/events/test-libvirt-auth-callbacks.c new file mode 100644 index 000000000..7c26bbe33 --- /dev/null +++ b/tests/events/test-libvirt-auth-callbacks.c @@ -0,0 +1,185 @@ +/* libguestfs + * Copyright (C) 2014 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include +#include +#include +#include + +#include + +#include "guestfs.h" +#include "guestfs-internal-frontend.h" + +#define EXPECT_OK 1 +#define EXPECT_FAIL -1 + +struct auth_data { + const char *username; + const char *password; +}; + +static void do_test (const char *prog, const char *libvirt_uri, const struct auth_data *auth_data, int expected); +static void auth_callback (guestfs_h *g, void *opaque, uint64_t event, int event_handle, int flags, const char *buf, size_t buf_len, const uint64_t *array, size_t array_len); + +int +main (int argc, char *argv[]) +{ + unsigned long ver; + const char *srcdir; + char *cwd; + char *test_uri; + + virInitialize (); + + /* Check that the version of libvirt we are linked against + * supports the new test-driver auth feature. + */ + virGetVersion (&ver, NULL, NULL); + if (ver < 1002001) { + fprintf (stderr, "%s: test skipped because libvirt is too old (%lu)\n", + argv[0], ver); + exit (77); + } + + /* $srcdir must have been passed (by automake). */ + srcdir = getenv ("srcdir"); + if (!srcdir) { + fprintf (stderr, + "%s: environment variable $srcdir is not defined.\n" + "Normally it is defined by automake. If you are running the\n" + "tests directly, set $srcdir to point to the source tests/events\n" + "directory.\n", argv[0]); + exit (EXIT_FAILURE); + } + + cwd = get_current_dir_name (); + if (cwd == NULL) { + perror ("get_current_dir_name"); + exit (EXIT_FAILURE); + } + + if (asprintf (&test_uri, "test://%s/%s/libvirt-auth.xml", cwd, srcdir) == -1) { + perror ("asprintf"); + exit (EXIT_FAILURE); + } + + free (cwd); + + /* Perform the tests. */ + struct auth_data ad1 = { .username = "rich", .password = "123456" }; + do_test (argv[0], test_uri, &ad1, EXPECT_OK); + struct auth_data ad2 = { .username = "rich", .password = "654321" }; + do_test (argv[0], test_uri, &ad2, EXPECT_FAIL); + struct auth_data ad3 = { .username = "jane", .password = NULL }; + do_test (argv[0], test_uri, &ad3, EXPECT_OK); + struct auth_data ad4 = { .username = "nouser", .password = "123456" }; + do_test (argv[0], test_uri, &ad4, EXPECT_FAIL); + + free (test_uri); + exit (EXIT_SUCCESS); +} + +static void +do_test (const char *prog, const char *libvirt_uri, + const struct auth_data *auth_data, + int expected) +{ + guestfs_h *g; + const char *creds[] = + { "authname", "passphrase", "noechoprompt", NULL }; + int r, eh; + + g = guestfs_create (); + if (!g) + exit (EXIT_FAILURE); + + r = guestfs_set_libvirt_supported_credentials (g, (char **) creds); + if (r == -1) + exit (EXIT_FAILURE); + + eh = guestfs_set_event_callback (g, auth_callback, + GUESTFS_EVENT_LIBVIRT_AUTH, 0, + (void *) auth_data); + if (eh == -1) + exit (EXIT_FAILURE); + + r = guestfs_add_domain (g, "test", + GUESTFS_ADD_DOMAIN_LIBVIRTURI, libvirt_uri, + GUESTFS_ADD_DOMAIN_READONLY, 1, + -1); + if (r != expected) { + fprintf (stderr, + "%s: test failed: u=%s p=%s: got %d expected %d\n", + prog, auth_data->username, auth_data->password ? : "(none)", + r, expected); + exit (EXIT_FAILURE); + } + + guestfs_close (g); +} + +static void +auth_callback (guestfs_h *g, void *opaque, + uint64_t event, int event_handle, + int flags, + const char *buf, size_t buf_len, + const uint64_t *array, size_t array_len) +{ + CLEANUP_FREE_STRING_LIST char **creds = NULL; + const struct auth_data *auth_data = opaque; + size_t i; + int r; + const char *reply; + size_t len; + + /* Ask libguestfs what credentials libvirt is demanding. */ + creds = guestfs_get_libvirt_requested_credentials (g); + if (creds == NULL) + exit (EXIT_FAILURE); + + /* Try to answer from the authentication data. */ + for (i = 0; creds[i] != NULL; ++i) { + if (STREQ (creds[i], "authname")) { + reply = auth_data->username; + len = strlen (reply); + } + else if (STREQ (creds[i], "passphrase") || + STREQ (creds[i], "noechoprompt")) { + if (!auth_data->password) { + fprintf (stderr, "test failed: libvirt asked for a password, but auth_data->password == NULL\n"); + exit (EXIT_FAILURE); + } + + reply = auth_data->password; + len = strlen (reply); + } + else { + fprintf (stderr, "test failed: libvirt asked for '%s' which is not in creds list\n(This is probably a libvirt bug)\n", + creds[i]); + exit (EXIT_FAILURE); + } + + r = guestfs_set_libvirt_requested_credential (g, i, + reply, len); + if (r == -1) + exit (EXIT_FAILURE); + } +}