From 282342c1c573b008203f1f894cec290c14f99e6c Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 5 Dec 2007 18:21:27 +0000 Subject: [PATCH] Added PolicyKit authentication support --- ChangeLog | 16 ++++ configure.in | 25 ++++++ libvirt.spec.in | 13 +++ qemud/Makefile.am | 11 ++- qemud/internal.h | 7 ++ qemud/libvirtd.conf | 18 +++- qemud/libvirtd.policy | 42 +++++++++ qemud/qemud.c | 35 ++++++++ qemud/remote.c | 135 +++++++++++++++++++++++++++- qemud/remote_dispatch_localvars.h | 1 + qemud/remote_dispatch_proc_switch.h | 6 ++ qemud/remote_dispatch_prototypes.h | 1 + qemud/remote_protocol.c | 9 ++ qemud/remote_protocol.h | 9 ++ qemud/remote_protocol.x | 10 ++- src/remote_internal.c | 35 ++++++++ 16 files changed, 365 insertions(+), 8 deletions(-) create mode 100644 qemud/libvirtd.policy diff --git a/ChangeLog b/ChangeLog index 7252b985ac..42392ed5b6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +Wed Dec 5 13:20:00 EST 2007 Daniel P. Berrange + + * 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 * src/Makefile.am, tests/Makefile.am: Remove LIBOBJS/LTLIBOBJS diff --git a/configure.in b/configure.in index 659eb0bc3b..04dd873b65 100644 --- a/configure.in +++ b/configure.in @@ -25,6 +25,7 @@ dnl Required minimum versions of all libs we depend on 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 @@ -394,6 +395,25 @@ AC_SUBST(SASL_CFLAGS) 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, @@ -627,6 +647,11 @@ AC_MSG_NOTICE([ avahi: $AVAHI_CFLAGS $AVAHI_LIBS]) 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([]) diff --git a/libvirt.spec.in b/libvirt.spec.in index 637dc77639..7598cdb4d7 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -1,5 +1,11 @@ # -*- 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@ @@ -20,6 +26,9 @@ Requires: cyrus-sasl # 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 @@ -31,6 +40,9 @@ BuildRequires: dnsmasq 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 @@ -143,6 +155,7 @@ fi %{_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 diff --git a/qemud/Makefile.am b/qemud/Makefile.am index aefc0faef7..c605e1f9f3 100644 --- a/qemud/Makefile.am +++ b/qemud/Makefile.am @@ -30,16 +30,25 @@ libvirtd_SOURCES = \ 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) diff --git a/qemud/internal.h b/qemud/internal.h index 7ad33ed45f..ee7ff59c91 100644 --- a/qemud/internal.h +++ b/qemud/internal.h @@ -32,6 +32,10 @@ #include #endif +#ifdef HAVE_POLKIT +#include +#endif + #ifdef HAVE_SYS_SYSLIMITS_H #include #endif @@ -155,6 +159,9 @@ struct qemud_server { #if HAVE_SASL char **saslUsernameWhitelist; #endif +#if HAVE_POLKIT + DBusConnection *sysbus; +#endif }; void qemudLog(int priority, const char *fmt, ...) diff --git a/qemud/libvirtd.conf b/qemud/libvirtd.conf index 40b47e9477..1919d498af 100644 --- a/qemud/libvirtd.conf +++ b/qemud/libvirtd.conf @@ -82,8 +82,11 @@ # 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" @@ -103,7 +106,12 @@ # 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 # @@ -112,7 +120,9 @@ #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 diff --git a/qemud/libvirtd.policy b/qemud/libvirtd.policy new file mode 100644 index 0000000000..16138cb3b8 --- /dev/null +++ b/qemud/libvirtd.policy @@ -0,0 +1,42 @@ + + + + + + + Monitor local virtualized systems + System policy prevents monitoring of local virtualized systems + + + yes + yes + yes + + + + + Manage local virtualized systems + System policy prevents management of local virtualized systems + + + no + no + auth_self_keep_session + + + \ No newline at end of file diff --git a/qemud/qemud.c b/qemud/qemud.c index d0d2f80d47..2d76ca1488 100644 --- a/qemud/qemud.c +++ b/qemud/qemud.c @@ -77,8 +77,13 @@ static gid_t unix_sock_gid = 0; /* Only root by default */ 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 @@ -759,6 +764,21 @@ static struct qemud_server *qemudNetworkInit(struct qemud_server *server) { } #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; @@ -826,6 +846,10 @@ static struct qemud_server *qemudNetworkInit(struct qemud_server *server) { sock = sock->next; } +#ifdef HAVE_POLKIT + if (server->sysbus) + dbus_connection_unref(server->sysbus); +#endif free(server); } return NULL; @@ -1780,6 +1804,10 @@ static int remoteConfigGetAuth(virConfPtr conf, const char *key, int *auth, cons #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); @@ -1816,6 +1844,13 @@ remoteReadConfigFile (struct qemud_server *server, const char *filename) 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) diff --git a/qemud/remote.c b/qemud/remote.c index 358554c3e3..69985917ff 100644 --- a/qemud/remote.c +++ b/qemud/remote.c @@ -46,6 +46,11 @@ #include #include +#ifdef HAVE_POLKIT +#include +#include +#endif + #include "libvirt/virterror.h" #include "internal.h" @@ -132,7 +137,8 @@ remoteDispatchClientRequest (struct qemud_server *server, 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); @@ -2550,6 +2556,133 @@ remoteDispatchAuthSaslStep (struct qemud_server *server ATTRIBUTE_UNUSED, #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 diff --git a/qemud/remote_dispatch_localvars.h b/qemud/remote_dispatch_localvars.h index 534de78f60..a239e4d13d 100644 --- a/qemud/remote_dispatch_localvars.h +++ b/qemud/remote_dispatch_localvars.h @@ -37,6 +37,7 @@ remote_domain_set_memory_args lv_remote_domain_set_memory_args; 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; diff --git a/qemud/remote_dispatch_proc_switch.h b/qemud/remote_dispatch_proc_switch.h index b01e6d6ac7..d316c9f0eb 100644 --- a/qemud/remote_dispatch_proc_switch.h +++ b/qemud/remote_dispatch_proc_switch.h @@ -8,6 +8,12 @@ case REMOTE_PROC_AUTH_LIST: 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; diff --git a/qemud/remote_dispatch_prototypes.h b/qemud/remote_dispatch_prototypes.h index 709e4e6967..ba8c13f090 100644 --- a/qemud/remote_dispatch_prototypes.h +++ b/qemud/remote_dispatch_prototypes.h @@ -3,6 +3,7 @@ */ 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); diff --git a/qemud/remote_protocol.c b/qemud/remote_protocol.c index d3710327e1..63a31495f6 100644 --- a/qemud/remote_protocol.c +++ b/qemud/remote_protocol.c @@ -1308,6 +1308,15 @@ xdr_remote_auth_sasl_step_ret (XDR *xdrs, remote_auth_sasl_step_ret *objp) 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) { diff --git a/qemud/remote_protocol.h b/qemud/remote_protocol.h index 9222ad3945..c592e294f8 100644 --- a/qemud/remote_protocol.h +++ b/qemud/remote_protocol.h @@ -68,6 +68,7 @@ typedef struct remote_error remote_error; enum remote_auth_type { REMOTE_AUTH_NONE = 0, REMOTE_AUTH_SASL = 1, + REMOTE_AUTH_POLKIT = 2, }; typedef enum remote_auth_type remote_auth_type; @@ -719,6 +720,11 @@ struct remote_auth_sasl_step_ret { } 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 @@ -792,6 +798,7 @@ enum remote_procedure { 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; @@ -935,6 +942,7 @@ extern bool_t xdr_remote_auth_sasl_start_args (XDR *, remote_auth_sasl_start_ar 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*); @@ -1054,6 +1062,7 @@ extern bool_t xdr_remote_auth_sasl_start_args (); 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 (); diff --git a/qemud/remote_protocol.x b/qemud/remote_protocol.x index 2029d6e15d..d409c74387 100644 --- a/qemud/remote_protocol.x +++ b/qemud/remote_protocol.x @@ -132,7 +132,8 @@ struct remote_error { /* 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 }; @@ -656,6 +657,10 @@ struct remote_auth_sasl_step_ret { char data; }; +struct remote_auth_polkit_ret { + int complete; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -731,7 +736,8 @@ enum remote_procedure { 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. */ diff --git a/src/remote_internal.c b/src/remote_internal.c index 92e153fade..37167728e8 100644 --- a/src/remote_internal.c +++ b/src/remote_internal.c @@ -115,6 +115,9 @@ static int remoteAuthenticate (virConnectPtr conn, struct private_data *priv, in #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); @@ -2854,6 +2857,15 @@ remoteAuthenticate (virConnectPtr conn, struct private_data *priv, int in_open) 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; @@ -3444,6 +3456,29 @@ really_write_sasl (virConnectPtr conn, struct private_data *priv, } #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 */, -- 2.39.5