diff --git a/src/access/viraccessperm.h b/src/access/viraccessperm.h index fdc461b640..6d14f058c3 100644 --- a/src/access/viraccessperm.h +++ b/src/access/viraccessperm.h @@ -1,7 +1,7 @@ /* * viraccessperm.h: access control permissions * - * Copyright (C) 2012-2013 Red Hat, Inc. + * Copyright (C) 2012-2014 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 @@ -47,14 +47,14 @@ typedef enum { /** * @desc: List domains - * @message: Listing domains requires authorization + * @message: Listing domains or using domain events requires authorization * @anonymous: 1 */ VIR_ACCESS_PERM_CONNECT_SEARCH_DOMAINS, /** * @desc: List networks - * @message: Listing networks requires authorization + * @message: Listing networks or using network events requires authorization * @anonymous: 1 */ VIR_ACCESS_PERM_CONNECT_SEARCH_NETWORKS, diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index b934cc768f..f56aed37b9 100644 --- a/src/conf/domain_event.c +++ b/src/conf/domain_event.c @@ -360,6 +360,30 @@ virDomainEventDeviceRemovedDispose(void *obj) } +/** + * virDomainEventFilter: + * @conn: pointer to the connection + * @event: the event to check + * @opaque: opaque data holding ACL filter to use + * + * Internal function to run ACL filtering before dispatching an event + */ +static bool +virDomainEventFilter(virConnectPtr conn, virObjectEventPtr event, void *opaque) +{ + virDomainDef dom; + virDomainObjListFilter filter = opaque; + + /* For now, we just create a virDomainDef with enough contents to + * satisfy what viraccessdriverpolkit.c references. This is a bit + * fragile, but I don't know of anything better. */ + dom.name = event->meta.name; + memcpy(dom.uuid, event->meta.uuid, VIR_UUID_BUFLEN); + + return (filter)(conn, &dom); +} + + static void * virDomainEventNew(virClassPtr klass, int eventID, @@ -1265,6 +1289,7 @@ cleanup: * virDomainEventStateRegister: * @conn: connection to associate with callback * @state: object event state + * @filter: optional ACL filter to limit which events can be sent * @callback: the callback to add * @opaque: data blob to pass to @callback * @freecb: callback to free @opaque @@ -1277,6 +1302,7 @@ cleanup: int virDomainEventStateRegister(virConnectPtr conn, virObjectEventStatePtr state, + virDomainObjListFilter filter, virConnectDomainEventCallback callback, void *opaque, virFreeCallback freecb) @@ -1285,7 +1311,8 @@ virDomainEventStateRegister(virConnectPtr conn, return -1; return virObjectEventStateRegisterID(conn, state, NULL, - virDomainEventClass, + filter ? virDomainEventFilter : NULL, + filter, virDomainEventClass, VIR_DOMAIN_EVENT_ID_LIFECYCLE, VIR_OBJECT_EVENT_CALLBACK(callback), opaque, freecb, NULL, false); @@ -1296,6 +1323,7 @@ virDomainEventStateRegister(virConnectPtr conn, * virDomainEventStateRegisterID: * @conn: connection to associate with callback * @state: object event state + * @filter: optional ACL filter to limit which events can be sent * @dom: optional domain for filtering the event * @eventID: ID of the event type to register for * @cb: function to invoke when event fires @@ -1312,6 +1340,7 @@ virDomainEventStateRegister(virConnectPtr conn, int virDomainEventStateRegisterID(virConnectPtr conn, virObjectEventStatePtr state, + virDomainObjListFilter filter, virDomainPtr dom, int eventID, virConnectDomainEventGenericCallback cb, @@ -1323,7 +1352,8 @@ virDomainEventStateRegisterID(virConnectPtr conn, return -1; return virObjectEventStateRegisterID(conn, state, dom ? dom->uuid : NULL, - virDomainEventClass, eventID, + filter ? virDomainEventFilter : NULL, + filter, virDomainEventClass, eventID, VIR_OBJECT_EVENT_CALLBACK(cb), opaque, freecb, callbackID, false); } diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h index b2ea580e67..b39d5cda34 100644 --- a/src/conf/domain_event.h +++ b/src/conf/domain_event.h @@ -1,7 +1,7 @@ /* * domain_event.h: domain event queue processing helpers * - * Copyright (C) 2012 Red Hat, Inc. + * Copyright (C) 2012-2014 Red Hat, Inc. * Copyright (C) 2008 VirtualIron * Copyright (C) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. * @@ -177,20 +177,24 @@ virDomainEventDeviceRemovedNewFromDom(virDomainPtr dom, int virDomainEventStateRegister(virConnectPtr conn, virObjectEventStatePtr state, + virDomainObjListFilter filter, virConnectDomainEventCallback callback, void *opaque, virFreeCallback freecb) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(4); + int virDomainEventStateRegisterID(virConnectPtr conn, virObjectEventStatePtr state, + virDomainObjListFilter filter, virDomainPtr dom, int eventID, virConnectDomainEventGenericCallback cb, void *opaque, virFreeCallback freecb, int *callbackID) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(5); + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(6); + int virDomainEventStateDeregister(virConnectPtr conn, virObjectEventStatePtr state, diff --git a/src/conf/network_event.c b/src/conf/network_event.c index a0b60a0de0..f27b7e9e98 100644 --- a/src/conf/network_event.c +++ b/src/conf/network_event.c @@ -121,10 +121,36 @@ cleanup: } +/** + * virNetworkEventFilter: + * @conn: pointer to the connection + * @event: the event to check + * @opaque: opaque data holding ACL filter to use + * + * Internal function to run ACL filtering before dispatching an event + */ +static bool +virNetworkEventFilter(virConnectPtr conn, virObjectEventPtr event, + void *opaque) +{ + virNetworkDef net; + virNetworkObjListFilter filter = opaque; + + /* For now, we just create a virNetworkDef with enough contents to + * satisfy what viraccessdriverpolkit.c references. This is a bit + * fragile, but I don't know of anything better. */ + net.name = event->meta.name; + memcpy(net.uuid, event->meta.uuid, VIR_UUID_BUFLEN); + + return (filter)(conn, &net); +} + + /** * virNetworkEventStateRegisterID: * @conn: connection to associate with callback * @state: object event state + * @filter: optional ACL filter to limit which events can be sent * @net: network to filter on or NULL for all networks * @eventID: ID of the event type to register for * @cb: function to invoke when event occurs @@ -141,6 +167,7 @@ cleanup: int virNetworkEventStateRegisterID(virConnectPtr conn, virObjectEventStatePtr state, + virNetworkObjListFilter filter, virNetworkPtr net, int eventID, virConnectNetworkEventGenericCallback cb, @@ -152,7 +179,8 @@ virNetworkEventStateRegisterID(virConnectPtr conn, return -1; return virObjectEventStateRegisterID(conn, state, net ? net->uuid : NULL, - virNetworkEventClass, eventID, + filter ? virNetworkEventFilter : NULL, + filter, virNetworkEventClass, eventID, VIR_OBJECT_EVENT_CALLBACK(cb), opaque, freecb, callbackID, false); } @@ -190,6 +218,7 @@ virNetworkEventStateRegisterClient(virConnectPtr conn, return -1; return virObjectEventStateRegisterID(conn, state, net ? net->uuid : NULL, + NULL, NULL, virNetworkEventClass, eventID, VIR_OBJECT_EVENT_CALLBACK(cb), opaque, freecb, callbackID, true); diff --git a/src/conf/network_event.h b/src/conf/network_event.h index 51bd949bee..0812752e6d 100644 --- a/src/conf/network_event.h +++ b/src/conf/network_event.h @@ -24,6 +24,7 @@ #include "internal.h" #include "object_event.h" #include "object_event_private.h" +#include "network_conf.h" #ifndef __NETWORK_EVENT_H__ # define __NETWORK_EVENT_H__ @@ -31,14 +32,15 @@ int virNetworkEventStateRegisterID(virConnectPtr conn, virObjectEventStatePtr state, + virNetworkObjListFilter filter, virNetworkPtr net, int eventID, virConnectNetworkEventGenericCallback cb, void *opaque, virFreeCallback freecb, int *callbackID) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(5) - ATTRIBUTE_NONNULL(8); + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(6) + ATTRIBUTE_NONNULL(9); int virNetworkEventStateRegisterClient(virConnectPtr conn, diff --git a/src/conf/object_event.c b/src/conf/object_event.c index fa6af5c555..aff4956614 100644 --- a/src/conf/object_event.c +++ b/src/conf/object_event.c @@ -69,6 +69,8 @@ struct _virObjectEventCallback { int remoteID; bool uuid_filter; unsigned char uuid[VIR_UUID_BUFLEN]; + virObjectEventCallbackFilter filter; + void *filter_opaque; virConnectObjectEventGenericCallback cb; void *opaque; virFreeCallback freecb; @@ -350,7 +352,9 @@ virObjectEventCallbackLookup(virConnectPtr conn, * virObjectEventCallbackListAddID: * @conn: pointer to the connection * @cbList: the list - * @uuid: the uuid of the object to filter on + * @uuid: the optional uuid of the object to filter on + * @filter: optional last-ditch filter callback + * @filter_opaque: opaque data to pass to @filter * @klass: the base event class * @eventID: the event ID * @callback: the callback to add @@ -365,6 +369,8 @@ static int virObjectEventCallbackListAddID(virConnectPtr conn, virObjectEventCallbackListPtr cbList, unsigned char uuid[VIR_UUID_BUFLEN], + virObjectEventCallbackFilter filter, + void *filter_opaque, virClassPtr klass, int eventID, virConnectObjectEventGenericCallback callback, @@ -377,9 +383,10 @@ virObjectEventCallbackListAddID(virConnectPtr conn, int ret = -1; int remoteID = -1; - VIR_DEBUG("conn=%p cblist=%p uuid=%p " + VIR_DEBUG("conn=%p cblist=%p uuid=%p filter=%p filter_opaque=%p " "klass=%p eventID=%d callback=%p opaque=%p", - conn, cbList, uuid, klass, eventID, callback, opaque); + conn, cbList, uuid, filter, filter_opaque, + klass, eventID, callback, opaque); /* Check incoming */ if (!cbList) { @@ -414,6 +421,8 @@ virObjectEventCallbackListAddID(virConnectPtr conn, event->uuid_filter = true; memcpy(event->uuid, uuid, VIR_UUID_BUFLEN); } + event->filter = filter; + event->filter_opaque = filter_opaque; if (callbackID) *callbackID = event->callbackID; @@ -675,6 +684,9 @@ virObjectEventDispatchMatchCallback(virObjectEventPtr event, if (cb->remoteID != event->remoteID) return false; + if (cb->filter && !(cb->filter)(cb->conn, event, cb->filter_opaque)) + return false; + if (cb->uuid_filter) { /* Deliberately ignoring 'id' for matching, since that * will cause problems when a domain switches between @@ -848,6 +860,8 @@ int virObjectEventStateRegisterID(virConnectPtr conn, virObjectEventStatePtr state, unsigned char *uuid, + virObjectEventCallbackFilter filter, + void *filter_opaque, virClassPtr klass, int eventID, virConnectObjectEventGenericCallback cb, @@ -872,7 +886,8 @@ virObjectEventStateRegisterID(virConnectPtr conn, } ret = virObjectEventCallbackListAddID(conn, state->callbacks, - uuid, klass, eventID, + uuid, filter, filter_opaque, + klass, eventID, cb, opaque, freecb, callbackID, serverFilter); diff --git a/src/conf/object_event_private.h b/src/conf/object_event_private.h index 445d7261f1..8e265f94bc 100644 --- a/src/conf/object_event_private.h +++ b/src/conf/object_event_private.h @@ -52,6 +52,20 @@ struct _virObjectEvent { virObjectEventDispatchFunc dispatch; }; +/** + * virObjectEventCallbackFilter: + * @conn: the connection pointer + * @event: the event about to be dispatched + * @opaque: opaque data registered with the filter + * + * Callback to do final filtering for a reason not tracked directly by + * virObjectEventStateRegisterID(). Return false if @event must not + * be sent to @conn. + */ +typedef bool (*virObjectEventCallbackFilter)(virConnectPtr conn, + virObjectEventPtr event, + void *opaque); + virClassPtr virClassForObjectEvent(void); @@ -59,6 +73,8 @@ int virObjectEventStateRegisterID(virConnectPtr conn, virObjectEventStatePtr state, unsigned char *uuid, + virObjectEventCallbackFilter filter, + void *filter_opaque, virClassPtr klass, int eventID, virConnectObjectEventGenericCallback cb, @@ -66,8 +82,8 @@ virObjectEventStateRegisterID(virConnectPtr conn, virFreeCallback freecb, int *callbackID, bool remoteFilter) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(4) - ATTRIBUTE_NONNULL(6); + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(6) + ATTRIBUTE_NONNULL(8); int virObjectEventStateCallbackID(virConnectPtr conn, diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 61e35165f8..4115fffe3c 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -3654,6 +3654,7 @@ libxlConnectDomainEventRegister(virConnectPtr conn, if (virDomainEventStateRegister(conn, driver->domainEventState, + virConnectDomainEventRegisterCheckACL, callback, opaque, freecb) < 0) return -1; @@ -4259,6 +4260,7 @@ libxlConnectDomainEventRegisterAny(virConnectPtr conn, virDomainPtr dom, int eve if (virDomainEventStateRegisterID(conn, driver->domainEventState, + virConnectDomainEventRegisterAnyCheckACL, dom, eventID, callback, opaque, freecb, &ret) < 0) ret = -1; diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 7e56a59539..5ae4b6562a 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -1293,6 +1293,7 @@ lxcConnectDomainEventRegister(virConnectPtr conn, if (virDomainEventStateRegister(conn, driver->domainEventState, + virConnectDomainEventRegisterCheckACL, callback, opaque, freecb) < 0) return -1; @@ -1334,6 +1335,7 @@ lxcConnectDomainEventRegisterAny(virConnectPtr conn, if (virDomainEventStateRegisterID(conn, driver->domainEventState, + virConnectDomainEventRegisterAnyCheckACL, dom, eventID, callback, opaque, freecb, &ret) < 0) ret = -1; diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 95e4b658d7..0b43a67e8c 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -2310,6 +2310,7 @@ networkConnectNetworkEventRegisterAny(virConnectPtr conn, goto cleanup; if (virNetworkEventStateRegisterID(conn, driver->networkEventState, + virConnectNetworkEventRegisterAnyCheckACL, net, eventID, callback, opaque, freecb, &ret) < 0) ret = -1; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 1949abee94..ebb77dca08 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -9959,6 +9959,7 @@ qemuConnectDomainEventRegister(virConnectPtr conn, if (virDomainEventStateRegister(conn, driver->domainEventState, + virConnectDomainEventRegisterCheckACL, callback, opaque, freecb) < 0) goto cleanup; @@ -10007,6 +10008,7 @@ qemuConnectDomainEventRegisterAny(virConnectPtr conn, if (virDomainEventStateRegisterID(conn, driver->domainEventState, + virConnectDomainEventRegisterAnyCheckACL, dom, eventID, callback, opaque, freecb, &ret) < 0) ret = -1; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 18eb454f58..ca86e3c029 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -4427,7 +4427,7 @@ remoteConnectDomainEventRegister(virConnectPtr conn, remoteDriverLock(priv); - if ((count = virDomainEventStateRegister(conn, priv->eventState, + if ((count = virDomainEventStateRegister(conn, priv->eventState, NULL, callback, opaque, freecb)) < 0) goto done; @@ -5245,7 +5245,7 @@ remoteConnectDomainEventRegisterAny(virConnectPtr conn, remoteDriverLock(priv); - if ((count = virDomainEventStateRegisterID(conn, priv->eventState, + if ((count = virDomainEventStateRegisterID(conn, priv->eventState, NULL, dom, eventID, callback, opaque, freecb, &callbackID)) < 0) diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index ae27a7721f..f94a38a63a 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -1955,7 +1955,7 @@ struct remote_node_device_destroy_args { /* * Events Register/Deregister: - * It would seem rpcgen does not like both args, and ret + * It would seem rpcgen does not like both args and ret * to be null. It will not generate the prototype otherwise. * Pass back a redundant boolean to force prototype generation. */ @@ -3642,7 +3642,8 @@ enum remote_procedure { /** * @generate: none * @priority: high - * @acl: connect:read + * @acl: connect:search_domains + * @aclfilter: domain:getattr */ REMOTE_PROC_CONNECT_DOMAIN_EVENT_REGISTER = 105, @@ -4074,7 +4075,8 @@ enum remote_procedure { /** * @generate: none * @priority: high - * @acl: connect:read + * @acl: connect:search_domains + * @aclfilter: domain:getattr */ REMOTE_PROC_CONNECT_DOMAIN_EVENT_REGISTER_ANY = 167, @@ -5045,7 +5047,8 @@ enum remote_procedure { /** * @generate: none * @priority: high - * @acl: connect:read + * @acl: connect:search_networks + * @aclfilter: network:getattr */ REMOTE_PROC_CONNECT_NETWORK_EVENT_REGISTER_ANY = 313, diff --git a/src/test/test_driver.c b/src/test/test_driver.c index b724f82b05..4c277bdd3a 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -6145,7 +6145,7 @@ testConnectDomainEventRegister(virConnectPtr conn, int ret = 0; testDriverLock(driver); - if (virDomainEventStateRegister(conn, driver->eventState, + if (virDomainEventStateRegister(conn, driver->eventState, NULL, callback, opaque, freecb) < 0) ret = -1; testDriverUnlock(driver); @@ -6183,7 +6183,7 @@ testConnectDomainEventRegisterAny(virConnectPtr conn, int ret; testDriverLock(driver); - if (virDomainEventStateRegisterID(conn, driver->eventState, + if (virDomainEventStateRegisterID(conn, driver->eventState, NULL, dom, eventID, callback, opaque, freecb, &ret) < 0) ret = -1; @@ -6221,7 +6221,7 @@ testConnectNetworkEventRegisterAny(virConnectPtr conn, int ret; testDriverLock(driver); - if (virNetworkEventStateRegisterID(conn, driver->eventState, + if (virNetworkEventStateRegisterID(conn, driver->eventState, NULL, net, eventID, callback, opaque, freecb, &ret) < 0) ret = -1; diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index ad29ebfb77..31ebf4ab6e 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -2618,6 +2618,7 @@ umlConnectDomainEventRegister(virConnectPtr conn, umlDriverLock(driver); if (virDomainEventStateRegister(conn, driver->domainEventState, + virConnectDomainEventRegisterCheckACL, callback, opaque, freecb) < 0) ret = -1; umlDriverUnlock(driver); @@ -2662,6 +2663,7 @@ umlConnectDomainEventRegisterAny(virConnectPtr conn, umlDriverLock(driver); if (virDomainEventStateRegisterID(conn, driver->domainEventState, + virConnectDomainEventRegisterAnyCheckACL, dom, eventID, callback, opaque, freecb, &ret) < 0) ret = -1; diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 0fcaf8e70d..241eb5e472 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -7328,7 +7328,7 @@ vboxConnectDomainEventRegister(virConnectPtr conn, * later you can iterate over them */ - ret = virDomainEventStateRegister(conn, data->domainEvents, + ret = virDomainEventStateRegister(conn, data->domainEvents, NULL, callback, opaque, freecb); VIR_DEBUG("virObjectEventStateRegister (ret = %d) (conn: %p, " "callback: %p, opaque: %p, " @@ -7425,7 +7425,7 @@ static int vboxConnectDomainEventRegisterAny(virConnectPtr conn, * later you can iterate over them */ - if (virDomainEventStateRegisterID(conn, data->domainEvents, + if (virDomainEventStateRegisterID(conn, data->domainEvents, NULL, dom, eventID, callback, opaque, freecb, &ret) < 0) ret = -1; diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index c45d10f950..7a57624b65 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -2323,6 +2323,7 @@ xenUnifiedConnectDomainEventRegister(virConnectPtr conn, } if (virDomainEventStateRegister(conn, priv->domainEvents, + virConnectDomainEventRegisterCheckACL, callback, opaque, freefunc) < 0) ret = -1; @@ -2382,6 +2383,7 @@ xenUnifiedConnectDomainEventRegisterAny(virConnectPtr conn, } if (virDomainEventStateRegisterID(conn, priv->domainEvents, + virConnectDomainEventRegisterAnyCheckACL, dom, eventID, callback, opaque, freefunc, &ret) < 0) ret = -1;