New APIs: Model libvirt authentication events through the API.

This commit models libvirt authentication events through the API,
adding one new event (GUESTFS_EVENT_LIBVIRT_AUTH) and several new
APIs:

  guestfs_set_libvirt_supported_credentials
  guestfs_get_libvirt_requested_credentials
  guestfs_get_libvirt_requested_credential_prompt
  guestfs_get_libvirt_requested_credential_challenge
  guestfs_get_libvirt_requested_credential_defresult
  guestfs_set_libvirt_requested_credential

See the documentation and example which shows how to use the new API.

This commit also changes existing calls to virConnectOpen* within the
library so that the new API is used.

Also included is an example (but not a test, because it's hard to see
how to automatically test the libvirt API).
This commit is contained in:
Richard W.M. Jones
2012-10-13 12:57:12 +01:00
parent 07d0546f5d
commit d83d17e9db
13 changed files with 809 additions and 5 deletions

1
.gitignore vendored
View File

@@ -99,6 +99,7 @@ Makefile.in
/examples/guestfs-recipes.1
/examples/guestfs-testing.1
/examples/inspect_vm
/examples/libvirt_auth
/examples/mount_local
/examples/stamp-guestfs-examples.pod
/examples/stamp-guestfs-faq.pod

View File

@@ -32,7 +32,7 @@ CLEANFILES = \
noinst_PROGRAMS = create_disk display_icon inspect_vm
if HAVE_LIBVIRT
noinst_PROGRAMS += copy_over
noinst_PROGRAMS += copy_over libvirt_auth
endif
if HAVE_HIVEX
noinst_PROGRAMS += virt-dhcp-address
@@ -52,6 +52,17 @@ copy_over_CFLAGS = \
copy_over_LDADD = \
$(top_builddir)/src/libguestfs.la \
$(LIBVIRT_LIBS)
libvirt_auth_SOURCES = libvirt_auth.c
libvirt_auth_CFLAGS = \
-DGUESTFS_WARN_DEPRECATED=1 \
-I$(top_srcdir)/src -I$(top_builddir)/src \
$(LIBVIRT_CFLAGS) \
-pthread \
$(WARN_CFLAGS) $(WERROR_CFLAGS)
libvirt_auth_LDADD = \
$(top_builddir)/src/libguestfs.la \
$(LIBVIRT_LIBS)
endif
create_disk_SOURCES = create_disk.c

167
examples/libvirt_auth.c Normal file
View File

@@ -0,0 +1,167 @@
/* Example of using the libvirt authentication event-driven API. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <guestfs.h>
static void
usage (void)
{
fprintf (stderr,
"Usage:\n"
"\n"
" libvirt_auth URI domain\n"
"\n"
"where:\n"
"\n"
" URI is the libvirt URI, eg. qemu+libssh2://USER@localhost/system\n"
" domain is the name of the guest\n"
"\n"
"Example:\n"
"\n"
" libvirt_auth 'qemu+libssh2://USER@localhost/system' 'foo'\n"
"\n"
"would connect (read-only) to libvirt URI given and open the guest\n"
"called 'foo' and list some information about its filesystems.\n"
"\n"
"The important point of this example is that any libvirt authentication\n"
"required to connect to the server should be done.\n"
"\n");
}
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[])
{
const char *uri, *dom;
guestfs_h *g;
const char *creds[] = { "authname", "passphrase",
"echoprompt", "noechoprompt", NULL };
int r, eh;
char **filesystems;
size_t i;
if (argc != 3) {
usage ();
exit (EXIT_FAILURE);
}
uri = argv[1];
dom = argv[2];
g = guestfs_create ();
if (!g)
exit (EXIT_FAILURE);
r = guestfs_set_libvirt_supported_credentials (g, (char **) creds);
if (r == -1)
exit (EXIT_FAILURE);
/* Set up the event handler. */
eh = guestfs_set_event_callback (g, auth_callback,
GUESTFS_EVENT_LIBVIRT_AUTH, 0, NULL);
if (eh == -1)
exit (EXIT_FAILURE);
/* Add the named domain. */
r = guestfs_add_domain (g, dom,
GUESTFS_ADD_DOMAIN_LIBVIRTURI, uri,
-1);
if (r == -1)
exit (EXIT_FAILURE);
/* Launch and do some simple inspection. */
r = guestfs_launch (g);
if (r == -1)
exit (EXIT_FAILURE);
filesystems = guestfs_list_filesystems (g);
for (i = 0; filesystems[i] != NULL; i += 2) {
printf ("%s:%s is a %s filesystem\n",
dom, filesystems[i], filesystems[i+1]);
free (filesystems[i]);
free (filesystems[i+1]);
}
free (filesystems);
exit (EXIT_SUCCESS);
}
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)
{
char **creds;
size_t i;
char *prompt;
char *reply = NULL;
size_t replylen;
char *pass;
ssize_t len;
int r;
printf ("libvirt_auth.c: authentication required for libvirt URI '%s'\n\n",
buf);
/* Ask libguestfs what credentials libvirt is demanding. */
creds = guestfs_get_libvirt_requested_credentials (g);
if (creds == NULL)
exit (EXIT_FAILURE);
/* Now ask the user for answers. */
for (i = 0; creds[i] != NULL; ++i)
{
printf ("libvirt_auth.c: credential '%s'\n", creds[i]);
if (strcmp (creds[i], "authname") == 0 ||
strcmp (creds[i], "echoprompt") == 0) {
prompt = guestfs_get_libvirt_requested_credential_prompt (g, i);
if (prompt && strcmp (prompt, "") != 0)
printf ("%s: ", prompt);
free (prompt);
len = getline (&reply, &replylen, stdin);
if (len == -1) {
perror ("getline");
exit (EXIT_FAILURE);
}
if (len > 0 && reply[len-1] == '\n')
reply[--len] = '\0';
r = guestfs_set_libvirt_requested_credential (g, i, reply, len);
if (r == -1)
exit (EXIT_FAILURE);
} else if (strcmp (creds[i], "passphrase") == 0 ||
strcmp (creds[i], "noechoprompt") == 0) {
prompt = guestfs_get_libvirt_requested_credential_prompt (g, i);
if (prompt && strcmp (prompt, "") != 0)
printf ("%s: ", prompt);
free (prompt);
pass = getpass ("");
if (pass == NULL) {
perror ("getpass");
exit (EXIT_FAILURE);
}
len = strlen (pass);
r = guestfs_set_libvirt_requested_credential (g, i, pass, len);
if (r == -1)
exit (EXIT_FAILURE);
}
free (creds[i]);
}
free (reply);
free (creds);
}

View File

@@ -2379,6 +2379,107 @@ unplug the drive: see L<guestfs(3)/HOTPLUGGING>. The disk B<must not>
be in use (eg. mounted) when you do this. We try to detect if the
disk is in use and stop you from doing this." };
{ defaults with
name = "set_libvirt_supported_credentials";
style = RErr, [StringList "creds"], [];
tests = [];
shortdesc = "set libvirt credentials supported by calling program";
longdesc = "\
Call this function before setting an event handler for
C<GUESTFS_EVENT_LIBVIRT_AUTH>, to supply the list of credential types
that the program knows how to process.
The C<creds> list must be a non-empty list of strings.
Possible strings are:
=over 4
=item C<username>
=item C<authname>
=item C<language>
=item C<cnonce>
=item C<passphrase>
=item C<echoprompt>
=item C<noechoprompt>
=item C<realm>
=item C<external>
=back
See libvirt documentation for the meaning of these credential types.
See L<guestfs(3)/LIBVIRT AUTHENTICATION> for documentation and example code." };
{ defaults with
name = "get_libvirt_requested_credentials";
style = RStringList "creds", [], [];
tests = [];
shortdesc = "get list of credentials requested by libvirt";
longdesc = "\
This should only be called during the event callback
for events of type C<GUESTFS_EVENT_LIBVIRT_AUTH>.
Return the list of credentials requested by libvirt. Possible
values are a subset of the strings provided when you called
C<guestfs_set_libvirt_supported_credentials>.
See L<guestfs(3)/LIBVIRT AUTHENTICATION> for documentation and example code." };
{ defaults with
name = "get_libvirt_requested_credential_prompt";
style = RString "prompt", [Int "index"], [];
tests = [];
shortdesc = "prompt of i'th requested credential";
longdesc = "\
Get the prompt (provided by libvirt) for the C<index>'th
requested credential. If libvirt did not provide a prompt,
this returns the empty string C<\"\">.
See L<guestfs(3)/LIBVIRT AUTHENTICATION> for documentation and example code." };
{ defaults with
name = "get_libvirt_requested_credential_challenge";
style = RString "challenge", [Int "index"], [];
tests = [];
shortdesc = "challenge of i'th requested credential";
longdesc = "\
Get the challenge (provided by libvirt) for the C<index>'th
requested credential. If libvirt did not provide a challenge,
this returns the empty string C<\"\">.
See L<guestfs(3)/LIBVIRT AUTHENTICATION> for documentation and example code." };
{ defaults with
name = "get_libvirt_requested_credential_defresult";
style = RString "defresult", [Int "index"], [];
tests = [];
shortdesc = "default result of i'th requested credential";
longdesc = "\
Get the default result (provided by libvirt) for the C<index>'th
requested credential. If libvirt did not provide a default result,
this returns the empty string C<\"\">.
See L<guestfs(3)/LIBVIRT AUTHENTICATION> for documentation and example code." };
{ defaults with
name = "set_libvirt_requested_credential";
style = RErr, [Int "index"; BufferIn "cred"], [];
tests = [];
shortdesc = "pass requested credential back to libvirt";
longdesc = "\
After requesting the C<index>'th credential from the user,
call this function to pass the answer back to libvirt.
See L<guestfs(3)/LIBVIRT AUTHENTICATION> for documentation and example code." };
]
(* daemon_functions are any functions which cause some action

View File

@@ -37,6 +37,8 @@ let events = [
"trace"; (* call trace messages *)
"enter"; (* enter a function *)
"libvirt_auth"; (* libvirt authentication request *)
]
let events = mapi (fun i name -> name, 1 lsl i) events

View File

@@ -28,7 +28,8 @@ let log g ev eh buf array =
| Guestfs.EVENT_APPLIANCE -> "appliance"
| Guestfs.EVENT_LIBRARY -> "library"
| Guestfs.EVENT_TRACE -> "trace"
| Guestfs.EVENT_ENTER -> "enter" in
| Guestfs.EVENT_ENTER -> "enter"
| Guestfs.EVENT_LIBVIRT_AUTH -> "libvirt_auth" in
let eh : int = Obj.magic eh in

View File

@@ -236,6 +236,7 @@ src/launch-appliance.c
src/launch-libvirt.c
src/launch-unix.c
src/launch.c
src/libvirt-auth.c
src/libvirt-domain.c
src/listfs.c
src/match.c

View File

@@ -142,6 +142,7 @@ libguestfs_la_SOURCES = \
launch-appliance.c \
launch-libvirt.c \
launch-unix.c \
libvirt-auth.c \
libvirt-domain.c \
listfs.c \
match.c \

View File

@@ -293,6 +293,16 @@ struct guestfs_h
int ml_debug_calls; /* Extra debug info on each FUSE call. */
#endif
#ifdef HAVE_LIBVIRT
/* Used by src/libvirt-auth.c. */
#define NR_CREDENTIAL_TYPES 9
unsigned int nr_supported_credentials;
int supported_credentials[NR_CREDENTIAL_TYPES];
const char *saved_libvirt_uri; /* Doesn't need to be freed. */
unsigned int nr_requested_credentials;
virConnectCredentialPtr requested_credentials;
#endif
/**** Private data for attach-methods. ****/
/* NB: This cannot be a union because of a pathological case where
* the user changes attach-method while reusing the handle to launch
@@ -567,4 +577,9 @@ extern int guestfs___read_db_dump (guestfs_h *g, const char *dumpfile, void *opa
extern void guestfs___free_fuse (guestfs_h *g);
#endif
/* libvirt-auth.c */
#ifdef HAVE_LIBVIRT
extern virConnectPtr guestfs___open_libvirt_connection (guestfs_h *g, const char *uri, unsigned int flags);
#endif
#endif /* GUESTFS_INTERNAL_H_ */

View File

@@ -2232,6 +2232,16 @@ do not generate this event.
If no callback is registered: the event is ignored.
=item GUESTFS_EVENT_LIBVIRT_AUTH
(payload type: libvirt URI)
For any API function that opens a libvirt connection, this
event may be generated to indicate that libvirt demands
authentication information. See L</LIBVIRT AUTHENTICATION> below.
If no callback is registered: C<virConnectAuthPtrDefault> is
used (suitable for command-line programs only).
=back
=head2 EVENT API
@@ -2351,6 +2361,132 @@ this example, messages are directed to syslog:
syslog (priority, "event 0x%lx: %s", event, buf);
}
=head2 LIBVIRT AUTHENTICATION
Some libguestfs API calls can open libvirt connections. Currently the
only ones are L</guestfs_add_domain>; and L</guestfs_launch> if the
libvirt attach-method has been selected. Libvirt connections may
require authentication, for example if they need to access a remote
server or to access root services from non-root. Libvirt
authentication happens via a callback mechanism, see
L<http://libvirt.org/guide/html/Application_Development_Guide-Connections.html>
You may provide libvirt authentication data by registering a callback
for events of type C<GUESTFS_EVENT_LIBVIRT_AUTH>.
If no such event is registered, then libguestfs uses a libvirt
function that provides command-line prompts
(C<virConnectAuthPtrDefault>). This is only suitable for command-line
libguestfs programs.
To provide authentication, first call
L</guestfs_set_libvirt_supported_credentials> with the list of
credentials your program knows how to provide. Second, register a
callback for the C<GUESTFS_EVENT_LIBVIRT_AUTH> event. The event
handler will be called when libvirt is requesting authentication
information.
In the event handler, call
L</guestfs_get_libvirt_requested_credentials> to get a list of the
credentials that libvirt is asking for. You then need to ask (eg. the
user) for each credential, and call
L</guestfs_set_libvirt_requested_credential> with the answer. Note
that for each credential, additional information may be available
via the calls
L</guestfs_get_libvirt_requested_credential_prompt>,
L</guestfs_get_libvirt_requested_credential_challenge> or
L</guestfs_get_libvirt_requested_credential_defresult>.
The example program below should make this clearer.
There is also a more substantial working example program supplied with
the libguestfs sources, called C<libvirt_auth.c>.
main ()
{
guestfs_h *g;
char *creds[] = { "authname", "passphrase", NULL };
int r, eh;
g = guestfs_create ();
if (!g) exit (EXIT_FAILURE);
/* Tell libvirt what credentials the program supports. */
r = guestfs_set_libvirt_supported_credentials (g, creds);
if (r == -1)
exit (EXIT_FAILURE);
/* Set up the event handler. */
eh = guestfs_set_event_callback (
g, do_auth,
GUESTFS_EVENT_LIBVIRT_AUTH, 0, NULL);
if (eh == -1)
exit (EXIT_FAILURE);
/* An example of a call that may ask for credentials. */
r = guestfs_add_domain (
g, "dom",
GUESTFS_ADD_DOMAIN_LIBVIRTURI, "qemu:///system",
-1);
if (r == -1)
exit (EXIT_FAILURE);
exit (EXIT_SUCCESS);
}
static void
do_auth (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)
{
char **creds;
size_t i;
char *prompt;
char *reply;
size_t replylen;
int r;
// buf will be the libvirt URI. buf_len may be ignored.
printf ("Authentication required for libvirt conn '%s'\n",
buf);
// Ask libguestfs what credentials libvirt is demanding.
creds = guestfs_get_libvirt_requested_credentials (g);
if (creds == NULL)
exit (EXIT_FAILURE);
// Now ask the user for answers.
for (i = 0; creds[i] != NULL; ++i)
{
if (strcmp (creds[i], "authname") == 0 ||
strcmp (creds[i], "passphrase") == 0)
{
prompt =
guestfs_get_libvirt_requested_credential_prompt (g, i);
if (prompt && strcmp (prompt, "") != 0)
printf ("%s: ", prompt);
free (prompt);
// Some code here to ask for the credential.
// ...
// Put the reply in 'reply', length 'replylen' (bytes).
r = guestfs_set_libvirt_requested_credential (g, i,
reply, replylen);
if (r == -1)
exit (EXIT_FAILURE);
}
free (creds[i]);
}
free (creds);
}
=head1 CANCELLING LONG TRANSFERS
Some operations can be cancelled by the caller while they are in

View File

@@ -157,8 +157,7 @@ launch_libvirt (guestfs_h *g, const char *libvirt_uri)
guestfs___print_timestamped_message (g, "connect to libvirt");
/* Connect to libvirt, get capabilities. */
/* XXX Support libvirt authentication in the future. */
conn = virConnectOpen (libvirt_uri);
conn = guestfs___open_libvirt_connection (g, libvirt_uri, 0);
if (!conn) {
libvirt_error (g, _("could not connect to libvirt (URI = %s)"),
libvirt_uri ? : "NULL");

369
src/libvirt-auth.c Normal file
View File

@@ -0,0 +1,369 @@
/* libguestfs
* Copyright (C) 2012 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#ifdef HAVE_LIBVIRT
#include <libvirt/libvirt.h>
#include <libvirt/virterror.h>
#endif
#ifdef HAVE_LIBXML2
#include <libxml/xpath.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#endif
#include "guestfs.h"
#include "guestfs-internal.h"
#include "guestfs-internal-actions.h"
#include "guestfs_protocol.h"
#if defined(HAVE_LIBVIRT) && defined(HAVE_LIBXML2)
static struct {
int credtype;
const char *credname;
} libvirt_credential_types[NR_CREDENTIAL_TYPES] = {
{ VIR_CRED_USERNAME, "username" },
{ VIR_CRED_AUTHNAME, "authname" },
{ VIR_CRED_LANGUAGE, "language" },
{ VIR_CRED_CNONCE, "cnonce" },
{ VIR_CRED_PASSPHRASE, "passphrase" },
{ VIR_CRED_ECHOPROMPT, "echoprompt" },
{ VIR_CRED_NOECHOPROMPT, "noechoprompt" },
{ VIR_CRED_REALM, "realm" },
{ VIR_CRED_EXTERNAL, "external" },
};
static int
get_credtype_from_string (const char *name)
{
size_t i;
for (i = 0; i < NR_CREDENTIAL_TYPES; ++i)
if (STREQ (name, libvirt_credential_types[i].credname))
return libvirt_credential_types[i].credtype;
return -1;
}
static const char *
get_string_of_credtype (int credtype)
{
size_t i;
for (i = 0; i < NR_CREDENTIAL_TYPES; ++i)
if (credtype == libvirt_credential_types[i].credtype)
return libvirt_credential_types[i].credname;
return NULL;
}
/* Note to callers: Should it be possible to say that you don't
* support any libvirt credential types at all? Not clear if that's
* an error or not, so don't depend on the current behaviour.
*/
int
guestfs__set_libvirt_supported_credentials (guestfs_h *g, char *const *creds)
{
size_t i;
int credtype;
/* Try to make this call atomic so it either completely succeeds
* or if it fails it leaves the current state intact.
*/
unsigned int ncredtypes = 0;
int credtypes[NR_CREDENTIAL_TYPES];
for (i = 0; creds[i] != NULL; ++i) {
credtype = get_credtype_from_string (creds[i]);
if (credtype == -1) {
error (g, _("unknown credential type '%s'"), creds[i]);
return -1;
}
if (ncredtypes >= NR_CREDENTIAL_TYPES) {
error (g, _("list of supported credentials is too long"));
return -1;
}
credtypes[ncredtypes++] = credtype;
}
g->nr_supported_credentials = ncredtypes;
memcpy (g->supported_credentials, credtypes, sizeof g->supported_credentials);
return 0;
}
/* This function is called back from libvirt. In turn it generates a
* libguestfs event to collect the desired credentials.
*/
static int
libvirt_auth_callback (virConnectCredentialPtr cred,
unsigned int ncred,
void *gv)
{
guestfs_h *g = gv;
size_t i;
if (cred == NULL || ncred == 0)
return 0;
/* libvirt probably does this already, but no harm in checking. */
for (i = 0; i < ncred; ++i)
cred[i].result = NULL;
g->requested_credentials = cred;
g->nr_requested_credentials = ncred;
guestfs___call_callbacks_message (g, GUESTFS_EVENT_LIBVIRT_AUTH,
g->saved_libvirt_uri,
strlen (g->saved_libvirt_uri));
/* libvirt documentation says: "Returns: 0 if all interactions were
* filled, or -1 upon error" However it also says "If an interaction
* cannot be filled, fill in NULL and 0". Does that mean it's OK
* (not an error) to leave a field NULL? libguestfs events cannot
* return errors, so that we would never have any other reason to
* return -1 here. XXX
*/
for (i = 0; i < ncred; ++i)
if (cred[i].result == NULL)
goto error;
return 0;
error:
for (i = 0; i < ncred; ++i) {
free (cred[i].result);
cred[i].result = NULL;
cred[i].resultlen = 0;
}
return -1;
}
static int
exists_libvirt_auth_event (guestfs_h *g)
{
size_t i;
for (i = 0; i < g->nr_events; ++i)
if ((g->events[i].event_bitmask & GUESTFS_EVENT_LIBVIRT_AUTH) != 0)
return 1;
return 0;
}
/* Open a libvirt connection (called from other parts of the library). */
virConnectPtr
guestfs___open_libvirt_connection (guestfs_h *g, const char *uri,
unsigned int flags)
{
virConnectAuth authdata;
virConnectAuthPtr authdataptr;
virConnectPtr conn;
/* Did the caller register a GUESTFS_EVENT_LIBVIRT_AUTH event and
* call guestfs_set_libvirt_supported_credentials?
*/
if (g->nr_supported_credentials > 0 && exists_libvirt_auth_event (g)) {
memset (&authdata, 0, sizeof authdata);
authdata.credtype = g->supported_credentials;
authdata.ncredtype = g->nr_supported_credentials;
authdata.cb = libvirt_auth_callback;
authdata.cbdata = g;
authdataptr = &authdata;
g->saved_libvirt_uri = uri;
}
else
authdataptr = virConnectAuthPtrDefault;
conn = virConnectOpenAuth (uri, authdataptr, flags);
/* Restore handle fields to "outside event handler" state. */
g->saved_libvirt_uri = NULL;
g->nr_requested_credentials = 0;
g->requested_credentials = NULL;
return conn;
}
/* The calls below are meant to be called recursively from
* the GUESTFS_EVENT_LIBVIRT_AUTH event.
*/
#define CHECK_IN_EVENT_HANDLER(r) \
if (g->nr_requested_credentials == 0) { \
error (g, _("%s should only be called from within the GUESTFS_EVENT_LIBVIRT_AUTH event handler"), \
__func__); \
return r; \
}
char **
guestfs__get_libvirt_requested_credentials (guestfs_h *g)
{
char **ret;
size_t i;
CHECK_IN_EVENT_HANDLER (NULL);
/* Convert the requested_credentials types to a list of strings. */
ret = safe_malloc (g, sizeof (char *) * (g->nr_requested_credentials+1));
for (i = 0; i < g->nr_requested_credentials; ++i) {
ret[i] = safe_strdup (g,
get_string_of_credtype (g->requested_credentials[i].type));
}
ret[i] = NULL;
return ret; /* caller frees */
}
char *
guestfs__get_libvirt_requested_credential_prompt (guestfs_h *g, int index)
{
size_t i;
CHECK_IN_EVENT_HANDLER (NULL);
if (index >= 0 && (unsigned int) index < g->nr_requested_credentials)
i = (size_t) index;
else {
error (g, _("credential index out of range"));
return NULL;
}
if (g->requested_credentials[i].prompt)
return safe_strdup (g, g->requested_credentials[i].prompt);
else
return safe_strdup (g, "");
}
char *
guestfs__get_libvirt_requested_credential_challenge (guestfs_h *g, int index)
{
size_t i;
CHECK_IN_EVENT_HANDLER (NULL);
if (index >= 0 && (unsigned int) index < g->nr_requested_credentials)
i = (size_t) index;
else {
error (g, _("credential index out of range"));
return NULL;
}
if (g->requested_credentials[i].challenge)
return safe_strdup (g, g->requested_credentials[i].challenge);
else
return safe_strdup (g, "");
}
char *
guestfs__get_libvirt_requested_credential_defresult (guestfs_h *g, int index)
{
size_t i;
CHECK_IN_EVENT_HANDLER (NULL);
if (index >= 0 && (unsigned int) index < g->nr_requested_credentials)
i = (size_t) index;
else {
error (g, _("credential index out of range"));
return NULL;
}
if (g->requested_credentials[i].defresult)
return safe_strdup (g, g->requested_credentials[i].defresult);
else
return safe_strdup (g, "");
}
int
guestfs__set_libvirt_requested_credential (guestfs_h *g, int index,
const char *cred, size_t cred_size)
{
size_t i;
CHECK_IN_EVENT_HANDLER (-1);
if (index >= 0 && (unsigned int) index < g->nr_requested_credentials)
i = (size_t) index;
else {
error (g, _("credential index out of range"));
return -1;
}
/* All the evidence is that libvirt will free this. */
g->requested_credentials[i].result = safe_malloc (g, cred_size+1 /* sic */);
memcpy (g->requested_credentials[i].result, cred, cred_size);
/* Some libvirt drivers are buggy (eg. libssh2), and they expect
* that the cred field will be \0 terminated. To avoid surprises,
* add a \0 at the end.
*/
g->requested_credentials[i].result[cred_size] = 0;
g->requested_credentials[i].resultlen = cred_size;
return 0;
}
#else /* no libvirt or libxml2 at compile time */
#define NOT_IMPL(r) \
error (g, _("libvirt authentication APIs not available since this version of libguestfs was compiled without libvirt or libxml2")); \
return r
int
guestfs__set_libvirt_supported_credentials (guestfs_h *g, char *const *creds)
{
NOT_IMPL(-1);
}
char **
guestfs__get_libvirt_requested_credentials (guestfs_h *g)
{
NOT_IMPL(NULL);
}
char *
guestfs__get_libvirt_requested_credential_prompt (guestfs_h *g, int index)
{
NOT_IMPL(NULL);
}
char *
guestfs__get_libvirt_requested_credential_challenge (guestfs_h *g, int index)
{
NOT_IMPL(NULL);
}
char *
guestfs__get_libvirt_requested_credential_defresult (guestfs_h *g, int index)
{
NOT_IMPL(NULL);
}
int
guestfs__set_libvirt_requested_credential (guestfs_h *g, int index, const char *cred, size_t cred_size)
{
NOT_IMPL(-1);
}
#endif /* no libvirt or libxml2 at compile time */

View File

@@ -99,7 +99,7 @@ guestfs__add_domain (guestfs_h *g, const char *domain_name,
}
/* Connect to libvirt, find the domain. */
conn = virConnectOpenReadOnly (libvirturi);
conn = guestfs___open_libvirt_connection (g, libvirturi, VIR_CONNECT_RO);
if (!conn) {
err = virGetLastError ();
error (g, _("could not connect to libvirt (code %d, domain %d): %s"),