+Wed Dec 5 13:20:00 EST 2007 Daniel P. Berrange <berrange@redhat.com>
+
+ * configure.in: do PolicyKit checks via pkg-config
+ * libvirt.spec.in: Add dep on PolicyKit if Fedora 8 or later
+ * qemud/Makefile.am: Add PolicyKit build flags and default
+ policy file
+ * qemud/libvirtd.conf: Add comment about polkit auth option
+ * qemud/libvirtd.policy: Default policy file
+ * qemud/qemud.c, qemud/remote.c: Implementation of PolicyKit
+ authentication
+ * qemud/remote_protocol.x: Add RPC calls for PolicyKit auth
+ * qemud/remote_dispatch*, qemud/remote_protocol.{c.h}: update
+ for new RPC calls.
+ * src/remote_internal.c: Fetch credentials for PolicyKit and
+ perform client part of auth process
+
Wed Dec 5 18:00:00 UTC 2007 Richard W.M. Jones <rjones@redhat.com>
* src/Makefile.am, tests/Makefile.am: Remove LIBOBJS/LTLIBOBJS
LIBXML_REQUIRED="2.5.0"
GNUTLS_REQUIRED="1.0.25"
AVAHI_REQUIRED="0.6.0"
+POLKIT_REQUIRED="0.6"
dnl Checks for C compiler.
AC_PROG_CC
AC_SUBST(SASL_LIBS)
+dnl PolicyKit library
+POLKIT_CFLAGS=
+POLKIT_LIBS=
+AC_ARG_WITH(polkit,
+ [ --with-polkit use PolicyKit for UNIX socket access checks],
+ [],
+ [with_polkit=check])
+
+if test "$with_polkit" = "check"; then
+ PKG_CHECK_EXISTS(polkit-dbus >= $POLKIT_REQUIRED, [with_polkit=yes], [with_polkit=no])
+fi
+
+if test "$with_polkit" = "yes"; then
+ PKG_CHECK_MODULES(POLKIT, polkit-dbus >= $POLKIT_REQUIRED)
+ AC_DEFINE_UNQUOTED(HAVE_POLKIT, 1, [use PolicyKit for UNIX socket access checks])
+fi
+AM_CONDITIONAL(HAVE_POLKIT, [test "$with_polkit" = "yes"])
+AC_SUBST(POLKIT_CFLAGS)
+AC_SUBST(POLKIT_LIBS)
dnl Avahi library
AC_ARG_WITH(avahi,
else
AC_MSG_NOTICE([ avahi: no])
fi
+if test "$with_polkit" = "yes" ; then
+AC_MSG_NOTICE([ polkit: $POLKIT_CFLAGS $POLKIT_LIBS])
+else
+AC_MSG_NOTICE([ polkit: no])
+fi
AC_MSG_NOTICE([])
AC_MSG_NOTICE([Miscellaneous])
AC_MSG_NOTICE([])
# -*- rpm-spec -*-
+%if %{fedora} >= 8
+%define with_polkit 1
+%else
+%define with_polkit 0
+%endif
+
Summary: Library providing a simple API virtualization
Name: libvirt
Version: @VERSION@
# Not technically required, but makes 'out-of-box' config
# work correctly & doesn't have onerous dependancies
Requires: cyrus-sasl-md5
+%if %{with_polkit}
+Requires: PolicyKit >= 0.6
+%endif
BuildRequires: xen-devel
BuildRequires: libxml2-devel
BuildRequires: readline-devel
BuildRequires: bridge-utils
BuildRequires: qemu
BuildRequires: cyrus-sasl-devel
+%if %{with_polkit}
+BuildRequires: PolicyKit-devel >= 0.6
+%endif
Obsoletes: libvir
ExclusiveArch: i386 x86_64 ia64
%{_datadir}/libvirt/networks/default.xml
%dir %{_localstatedir}/run/libvirt/
%dir %{_localstatedir}/lib/libvirt/
+%{_datadir}/PolicyKit/policy/libvirtd.policy
%dir %attr(0700, root, root) %{_localstatedir}/log/libvirt/qemu/
%attr(4755, root, root) %{_libexecdir}/libvirt_proxy
%attr(0755, root, root) %{_sbindir}/libvirtd
libvirtd_CFLAGS = \
-I$(top_srcdir)/include -I$(top_builddir)/include \
$(LIBXML_CFLAGS) $(GNUTLS_CFLAGS) $(SASL_CFLAGS) \
+ $(POLKIT_CFLAGS) \
$(WARN_CFLAGS) -DLOCAL_STATE_DIR="\"$(localstatedir)\"" \
-DSYSCONF_DIR="\"$(sysconfdir)\"" \
-DQEMUD_PID_FILE="\"$(QEMUD_PID_FILE)\"" \
-DREMOTE_PID_FILE="\"$(REMOTE_PID_FILE)\"" \
-DGETTEXT_PACKAGE=\"$(PACKAGE)\"
-libvirtd_LDFLAGS = $(WARN_CFLAGS) $(LIBXML_LIBS) $(GNUTLS_LIBS) $(SASL_LIBS)
+libvirtd_LDFLAGS = $(WARN_CFLAGS) $(LIBXML_LIBS) $(GNUTLS_LIBS) $(SASL_LIBS) \
+ $(POLKIT_LIBS)
libvirtd_DEPENDENCIES = ../src/libvirt.la
libvirtd_LDADD = ../src/libvirt.la
+
+if HAVE_POLKIT
+policydir = $(datadir)/PolicyKit/policy
+policy_DATA = libvirtd.policy
+endif
+EXTRA_DIST += libvirtd.policy
+
if HAVE_AVAHI
libvirtd_SOURCES += mdns.c mdns.h
libvirtd_CFLAGS += $(AVAHI_CFLAGS)
#include <sasl/sasl.h>
#endif
+#ifdef HAVE_POLKIT
+#include <dbus/dbus.h>
+#endif
+
#ifdef HAVE_SYS_SYSLIMITS_H
#include <sys/syslimits.h>
#endif
#if HAVE_SASL
char **saslUsernameWhitelist;
#endif
+#if HAVE_POLKIT
+ DBusConnection *sysbus;
+#endif
};
void qemudLog(int priority, const char *fmt, ...)
# Set the UNIX socket permissions for the R/W socket. This is used
# for full management of VMs
#
-# Default allows only root. If setting group ownership may want to
-# relax this to:
+# Default allows only root. If PolicyKit is enabled on the socket,
+# the default will change to allow everyone (eg, 0777)
+#
+# If not using PolicyKit and setting group ownership for access
+# control then you may want to relax this to:
#unix_sock_rw_perms = "0770"
# socket only GSSAPI & DIGEST-MD5 mechanisms will be used.
# For non-TCP or TLS sockets, any scheme is allowed.
#
-
+# - polkit: use PolicyKit to authenticate. This is only suitable
+# for use on the UNIX sockets. The default policy will
+# require a user to supply their own password to gain
+# full read/write access (aka sudo like), while anyone
+# is allowed read/only access.
+#
# Set an authentication scheme for UNIX read-only sockets
# By default socket permissions allow anyone to connect
#
#auth_unix_ro = "none"
# Set an authentication scheme for UNIX read-write sockets
-# By default socket permissions only allow root.
+# By default socket permissions only allow root. If PolicyKit
+# support was compiled into libvirt, the default will be to
+# use 'polkit' auth.
#
# If the unix_sock_rw_perms are changed you may wish to enable
# an authentication mechanism here
--- /dev/null
+<!DOCTYPE policyconfig PUBLIC
+ "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
+
+<!--
+Policy definitions for libvirt daemon
+
+Copyright (c) 2007 Daniel P. Berrange <berrange redhat com>
+
+libvirt is licensed to you under the GNU Lesser General Public License
+version 2. See COPYING for details.
+
+NOTE: If you make changes to this file, make sure to validate the file
+using the polkit-policy-file-validate(1) tool. Changes made to this
+file are instantly applied.
+-->
+
+<policyconfig>
+ <action id="org.libvirt.unix.monitor">
+ <description>Monitor local virtualized systems</description>
+ <message>System policy prevents monitoring of local virtualized systems</message>
+ <defaults>
+ <!-- Any program can use libvirt in read-only mode for monitoring,
+ even if not part of a session -->
+ <allow_any>yes</allow_any>
+ <allow_inactive>yes</allow_inactive>
+ <allow_active>yes</allow_active>
+ </defaults>
+ </action>
+
+ <action id="org.libvirt.unix.manage">
+ <description>Manage local virtualized systems</description>
+ <message>System policy prevents management of local virtualized systems</message>
+ <defaults>
+ <!-- Only a program in the active host session can use libvirt in
+ read-write mode for management, and we require user password -->
+ <allow_any>no</allow_any>
+ <allow_inactive>no</allow_inactive>
+ <allow_active>auth_self_keep_session</allow_active>
+ </defaults>
+ </action>
+</policyconfig>
\ No newline at end of file
static int unix_sock_rw_mask = 0700; /* Allow user only */
static int unix_sock_ro_mask = 0777; /* Allow world */
+#if HAVE_POLKIT
+static int auth_unix_rw = REMOTE_AUTH_POLKIT;
+static int auth_unix_ro = REMOTE_AUTH_POLKIT;
+#else
static int auth_unix_rw = REMOTE_AUTH_NONE;
static int auth_unix_ro = REMOTE_AUTH_NONE;
+#endif /* HAVE_POLKIT */
#if HAVE_SASL
static int auth_tcp = REMOTE_AUTH_SASL;
#else
}
#endif
+#ifdef HAVE_POLKIT
+ if (auth_unix_rw == REMOTE_AUTH_POLKIT ||
+ auth_unix_ro == REMOTE_AUTH_POLKIT) {
+ DBusError derr;
+ dbus_error_init(&derr);
+ server->sysbus = dbus_bus_get(DBUS_BUS_SYSTEM, &derr);
+ if (!(server->sysbus)) {
+ qemudLog(QEMUD_ERR, "Failed to connect to system bus for PolicyKit auth: %s",
+ derr.message);
+ dbus_error_free(&derr);
+ goto cleanup;
+ }
+ }
+#endif
+
if (ipsock) {
if (listen_tcp && remoteListenTCP (server, tcp_port, QEMUD_SOCK_TYPE_TCP, auth_tcp) < 0)
goto cleanup;
sock = sock->next;
}
+#ifdef HAVE_POLKIT
+ if (server->sysbus)
+ dbus_connection_unref(server->sysbus);
+#endif
free(server);
}
return NULL;
#if HAVE_SASL
} else if (STREQ(p->str, "sasl")) {
*auth = REMOTE_AUTH_SASL;
+#endif
+#if HAVE_POLKIT
+ } else if (STREQ(p->str, "polkit")) {
+ *auth = REMOTE_AUTH_POLKIT;
#endif
} else {
qemudLog (QEMUD_ERR, "remoteReadConfigFile: %s: %s: unsupported auth %s\n", filename, key, p->str);
if (remoteConfigGetAuth(conf, "auth_unix_rw", &auth_unix_rw, filename) < 0)
return -1;
+#if HAVE_POLKIT
+ /* Change default perms to be wide-open if PolicyKit is enabled.
+ * Admin can always override in config file
+ */
+ if (auth_unix_rw == REMOTE_AUTH_POLKIT)
+ unix_sock_rw_mask = 0777;
+#endif
if (remoteConfigGetAuth(conf, "auth_unix_ro", &auth_unix_ro, filename) < 0)
return -1;
if (remoteConfigGetAuth(conf, "auth_tcp", &auth_tcp, filename) < 0)
#include <assert.h>
#include <fnmatch.h>
+#ifdef HAVE_POLKIT
+#include <polkit/polkit.h>
+#include <polkit-dbus/polkit-dbus.h>
+#endif
+
#include "libvirt/virterror.h"
#include "internal.h"
if (req.proc != REMOTE_PROC_AUTH_LIST &&
req.proc != REMOTE_PROC_AUTH_SASL_INIT &&
req.proc != REMOTE_PROC_AUTH_SASL_START &&
- req.proc != REMOTE_PROC_AUTH_SASL_STEP
+ req.proc != REMOTE_PROC_AUTH_SASL_STEP &&
+ req.proc != REMOTE_PROC_AUTH_POLKIT
) {
remoteDispatchError (client, &req, "authentication required");
xdr_destroy (&xdr);
#endif /* HAVE_SASL */
+#if HAVE_POLKIT
+static int qemudGetSocketIdentity(int fd, uid_t *uid, pid_t *pid) {
+#ifdef SO_PEERCRED
+ struct ucred cr;
+ unsigned int cr_len = sizeof (cr);
+
+ if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) < 0) {
+ qemudLog(QEMUD_ERR, "Failed to verify client credentials: %s", strerror(errno));
+ return -1;
+ }
+
+ *pid = cr.pid;
+ *uid = cr.uid;
+#else
+ /* XXX Many more OS support UNIX socket credentials we could port to. See dbus ....*/
+#error "UNIX socket credentials not supported/implemented on this platform yet..."
+#endif
+ return 0;
+}
+
+
+static int
+remoteDispatchAuthPolkit (struct qemud_server *server ATTRIBUTE_UNUSED,
+ struct qemud_client *client,
+ remote_message_header *req,
+ void *args ATTRIBUTE_UNUSED,
+ remote_auth_polkit_ret *ret)
+{
+ pid_t callerPid;
+ uid_t callerUid;
+
+ REMOTE_DEBUG("Start PolicyKit auth %d", client->fd);
+ if (client->auth != REMOTE_AUTH_POLKIT) {
+ qemudLog(QEMUD_ERR, "client tried invalid PolicyKit init request");
+ remoteDispatchFailAuth(client, req);
+ return -2;
+ }
+
+ if (qemudGetSocketIdentity(client->fd, &callerUid, &callerPid) < 0) {
+ qemudLog(QEMUD_ERR, "cannot get peer socket identity");
+ remoteDispatchFailAuth(client, req);
+ return -2;
+ }
+
+ /* Only do policy checks for non-root - allow root user
+ through with no checks, as a fail-safe - root can easily
+ change policykit policy anyway, so its pointless trying
+ to restrict root */
+ if (callerUid == 0) {
+ qemudLog(QEMUD_INFO, "Allowing PID %d running as root", callerPid);
+ ret->complete = 1;
+ client->auth = REMOTE_AUTH_NONE;
+ } else {
+ PolKitCaller *pkcaller = NULL;
+ PolKitAction *pkaction = NULL;
+ PolKitContext *pkcontext = NULL;
+ PolKitError *pkerr;
+ PolKitResult pkresult;
+ DBusError err;
+ const char *action = client->readonly ?
+ "org.libvirt.unix.monitor" :
+ "org.libvirt.unix.manage";
+
+ qemudLog(QEMUD_INFO, "Checking PID %d running as %d", callerPid, callerUid);
+ dbus_error_init(&err);
+ if (!(pkcaller = polkit_caller_new_from_pid(server->sysbus, callerPid, &err))) {
+ qemudLog(QEMUD_ERR, "Failed to lookup policy kit caller: %s", err.message);
+ dbus_error_free(&err);
+ remoteDispatchFailAuth(client, req);
+ return -2;
+ }
+
+ if (!(pkaction = polkit_action_new())) {
+ qemudLog(QEMUD_ERR, "Failed to create polkit action %s\n", strerror(errno));
+ polkit_caller_unref(pkcaller);
+ remoteDispatchFailAuth(client, req);
+ return -2;
+ }
+ polkit_action_set_action_id(pkaction, action);
+
+ if (!(pkcontext = polkit_context_new()) ||
+ !polkit_context_init(pkcontext, &pkerr)) {
+ qemudLog(QEMUD_ERR, "Failed to create polkit context %s\n",
+ pkerr ? polkit_error_get_error_message(pkerr) : strerror(errno));
+ if (pkerr)
+ polkit_error_free(pkerr);
+ polkit_caller_unref(pkcaller);
+ polkit_action_unref(pkaction);
+ dbus_error_free(&err);
+ remoteDispatchFailAuth(client, req);
+ return -2;
+ }
+
+ pkresult = polkit_context_can_caller_do_action(pkcontext, pkaction, pkcaller);
+ polkit_context_unref(pkcontext);
+ polkit_caller_unref(pkcaller);
+ polkit_action_unref(pkaction);
+ if (pkresult != POLKIT_RESULT_YES) {
+ qemudLog(QEMUD_ERR, "Policy kit denied action %s from pid %d, uid %d, result: %s\n",
+ action, callerPid, callerUid, polkit_result_to_string_representation(pkresult));
+ remoteDispatchFailAuth(client, req);
+ return -2;
+ }
+ qemudLog(QEMUD_INFO, "Policy allowed action %s from pid %d, uid %d, result %s",
+ action, callerPid, callerUid, polkit_result_to_string_representation(pkresult));
+ ret->complete = 1;
+ client->auth = REMOTE_AUTH_NONE;
+ }
+
+ return 0;
+}
+
+#else /* HAVE_POLKIT */
+
+static int
+remoteDispatchAuthPolkitInit (struct qemud_server *server ATTRIBUTE_UNUSED,
+ struct qemud_client *client,
+ remote_message_header *req,
+ void *args ATTRIBUTE_UNUSED,
+ remote_auth_polkit_ret *ret ATTRIBUTE_UNUSED)
+{
+ qemudLog(QEMUD_ERR, "client tried unsupported PolicyKit init request");
+ remoteDispatchFailAuth(client, req);
+ return -1;
+}
+#endif /* HAVE_POLKIT */
+
/*----- Helpers. -----*/
/* get_nonnull_domain and get_nonnull_network turn an on-wire
remote_domain_create_linux_args lv_remote_domain_create_linux_args;
remote_domain_create_linux_ret lv_remote_domain_create_linux_ret;
remote_domain_set_scheduler_parameters_args lv_remote_domain_set_scheduler_parameters_args;
+remote_auth_polkit_ret lv_remote_auth_polkit_ret;
remote_auth_sasl_start_args lv_remote_auth_sasl_start_args;
remote_auth_sasl_start_ret lv_remote_auth_sasl_start_ret;
remote_domain_interface_stats_args lv_remote_domain_interface_stats_args;
ret = (char *) &lv_remote_auth_list_ret;
memset (&lv_remote_auth_list_ret, 0, sizeof lv_remote_auth_list_ret);
break;
+case REMOTE_PROC_AUTH_POLKIT:
+ fn = (dispatch_fn) remoteDispatchAuthPolkit;
+ ret_filter = (xdrproc_t) xdr_remote_auth_polkit_ret;
+ ret = (char *) &lv_remote_auth_polkit_ret;
+ memset (&lv_remote_auth_polkit_ret, 0, sizeof lv_remote_auth_polkit_ret);
+ break;
case REMOTE_PROC_AUTH_SASL_INIT:
fn = (dispatch_fn) remoteDispatchAuthSaslInit;
ret_filter = (xdrproc_t) xdr_remote_auth_sasl_init_ret;
*/
static int remoteDispatchAuthList (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_auth_list_ret *ret);
+static int remoteDispatchAuthPolkit (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_auth_polkit_ret *ret);
static int remoteDispatchAuthSaslInit (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_auth_sasl_init_ret *ret);
static int remoteDispatchAuthSaslStart (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_auth_sasl_start_args *args, remote_auth_sasl_start_ret *ret);
static int remoteDispatchAuthSaslStep (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_auth_sasl_step_args *args, remote_auth_sasl_step_ret *ret);
return TRUE;
}
+bool_t
+xdr_remote_auth_polkit_ret (XDR *xdrs, remote_auth_polkit_ret *objp)
+{
+
+ if (!xdr_int (xdrs, &objp->complete))
+ return FALSE;
+ return TRUE;
+}
+
bool_t
xdr_remote_procedure (XDR *xdrs, remote_procedure *objp)
{
enum remote_auth_type {
REMOTE_AUTH_NONE = 0,
REMOTE_AUTH_SASL = 1,
+ REMOTE_AUTH_POLKIT = 2,
};
typedef enum remote_auth_type remote_auth_type;
} data;
};
typedef struct remote_auth_sasl_step_ret remote_auth_sasl_step_ret;
+
+struct remote_auth_polkit_ret {
+ int complete;
+};
+typedef struct remote_auth_polkit_ret remote_auth_polkit_ret;
#define REMOTE_PROGRAM 0x20008086
#define REMOTE_PROTOCOL_VERSION 1
REMOTE_PROC_AUTH_SASL_INIT = 67,
REMOTE_PROC_AUTH_SASL_START = 68,
REMOTE_PROC_AUTH_SASL_STEP = 69,
+ REMOTE_PROC_AUTH_POLKIT = 70,
};
typedef enum remote_procedure remote_procedure;
extern bool_t xdr_remote_auth_sasl_start_ret (XDR *, remote_auth_sasl_start_ret*);
extern bool_t xdr_remote_auth_sasl_step_args (XDR *, remote_auth_sasl_step_args*);
extern bool_t xdr_remote_auth_sasl_step_ret (XDR *, remote_auth_sasl_step_ret*);
+extern bool_t xdr_remote_auth_polkit_ret (XDR *, remote_auth_polkit_ret*);
extern bool_t xdr_remote_procedure (XDR *, remote_procedure*);
extern bool_t xdr_remote_message_direction (XDR *, remote_message_direction*);
extern bool_t xdr_remote_message_status (XDR *, remote_message_status*);
extern bool_t xdr_remote_auth_sasl_start_ret ();
extern bool_t xdr_remote_auth_sasl_step_args ();
extern bool_t xdr_remote_auth_sasl_step_ret ();
+extern bool_t xdr_remote_auth_polkit_ret ();
extern bool_t xdr_remote_procedure ();
extern bool_t xdr_remote_message_direction ();
extern bool_t xdr_remote_message_status ();
/* Authentication types available thus far.... */
enum remote_auth_type {
REMOTE_AUTH_NONE = 0,
- REMOTE_AUTH_SASL = 1
+ REMOTE_AUTH_SASL = 1,
+ REMOTE_AUTH_POLKIT = 2
};
char data<REMOTE_AUTH_SASL_DATA_MAX>;
};
+struct remote_auth_polkit_ret {
+ int complete;
+};
+
/*----- Protocol. -----*/
/* Define the program number, protocol version and procedure numbers here. */
REMOTE_PROC_AUTH_LIST = 66,
REMOTE_PROC_AUTH_SASL_INIT = 67,
REMOTE_PROC_AUTH_SASL_START = 68,
- REMOTE_PROC_AUTH_SASL_STEP = 69
+ REMOTE_PROC_AUTH_SASL_STEP = 69,
+ REMOTE_PROC_AUTH_POLKIT = 70
};
/* Custom RPC structure. */
#if HAVE_SASL
static int remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open);
#endif
+#if HAVE_POLKIT
+static int remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open);
+#endif /* HAVE_POLKIT */
static void error (virConnectPtr conn, virErrorNumber code, const char *info);
static void server_error (virConnectPtr conn, remote_error *err);
static virDomainPtr get_nonnull_domain (virConnectPtr conn, remote_nonnull_domain domain);
break;
#endif
+#if HAVE_POLKIT
+ case REMOTE_AUTH_POLKIT:
+ if (remoteAuthPolkit(conn, priv, in_open) < 0) {
+ free(ret.types.types_val);
+ return -1;
+ }
+ break;
+#endif
+
case REMOTE_AUTH_NONE:
/* Nothing todo, hurrah ! */
break;
}
#endif
+
+#if HAVE_POLKIT
+/* Perform the PolicyKit authentication process
+ */
+static int
+remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open)
+{
+ remote_auth_polkit_ret ret;
+
+ remoteDebug(priv, "Client initialize PolicyKit authentication");
+
+ memset (&ret, 0, sizeof ret);
+ if (call (conn, priv, in_open, REMOTE_PROC_AUTH_POLKIT,
+ (xdrproc_t) xdr_void, (char *)NULL,
+ (xdrproc_t) xdr_remote_auth_polkit_ret, (char *) &ret) != 0) {
+ return -1; /* virError already set by call */
+ }
+
+ remoteDebug(priv, "PolicyKit authentication complete");
+ return 0;
+}
+#endif /* HAVE_POLKIT */
+
static int
really_write (virConnectPtr conn, struct private_data *priv,
int in_open /* if we are in virConnectOpen */,