diff --git a/src/access/viraccessperm.h b/src/access/viraccessperm.h index 2f76c95cee..64db81fc3b 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,7 +47,7 @@ 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, diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index de55d08796..1736aa0a03 100644 --- a/src/conf/domain_event.c +++ b/src/conf/domain_event.c @@ -32,6 +32,20 @@ #define VIR_FROM_THIS VIR_FROM_NONE +/** + * 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, + virDomainEventPtr event, + void *opaque); + struct _virDomainMeta { int id; char *name; @@ -68,6 +82,8 @@ struct _virDomainEventCallback { int eventID; virConnectPtr conn; virDomainMetaPtr dom; + virObjectEventCallbackFilter filter; + void *filter_opaque; virConnectDomainEventGenericCallback cb; void *opaque; virFreeCallback freecb; @@ -344,6 +360,9 @@ virDomainEventCallbackListPurgeMarked(virDomainEventCallbackListPtr cbList) * virDomainEventCallbackListAddID: * @conn: pointer to the connection * @cbList: the list + * @dom: optional domain to filter on + * @filter optional last-ditch filter callback + * @filter_opaque: opaque data to pass to @filter * @eventID: the event ID * @callback: the callback to add * @opaque: opaque data tio pass to callback @@ -355,6 +374,8 @@ static int virDomainEventCallbackListAddID(virConnectPtr conn, virDomainEventCallbackListPtr cbList, virDomainPtr dom, + virObjectEventCallbackFilter filter, + void *filter_opaque, int eventID, virConnectDomainEventGenericCallback callback, void *opaque, @@ -401,6 +422,8 @@ virDomainEventCallbackListAddID(virConnectPtr conn, memcpy(event->dom->uuid, dom->uuid, VIR_UUID_BUFLEN); event->dom->id = dom->id; } + event->filter = filter; + event->filter_opaque = filter_opaque; /* Make space on list */ if (VIR_REALLOC_N(cbList->callbacks, cbList->count + 1) < 0) @@ -440,6 +463,8 @@ error: * virDomainEventCallbackListAdd: * @conn: pointer to the connection * @cbList: the list + * @filter optional last-ditch filter callback + * @filter_opaque: opaque data to pass to @filter * @callback: the callback to add * @opaque: opaque data tio pass to callback * @@ -448,11 +473,14 @@ error: static int virDomainEventCallbackListAdd(virConnectPtr conn, virDomainEventCallbackListPtr cbList, + virObjectEventCallbackFilter filter, + void *filter_opaque, virConnectDomainEventCallback callback, void *opaque, virFreeCallback freecb) { return virDomainEventCallbackListAddID(conn, cbList, NULL, + filter, filter_opaque, VIR_DOMAIN_EVENT_ID_LIFECYCLE, VIR_DOMAIN_EVENT_CALLBACK(callback), opaque, freecb, NULL); @@ -680,6 +708,32 @@ static virDomainEventPtr virDomainEventNewInternal(int eventID, return event; } + +/** + * 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, virDomainEventPtr 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->dom.name; + memcpy(dom.uuid, event->dom.uuid, VIR_UUID_BUFLEN); + + return (filter)(conn, &dom); +} + + virDomainEventPtr virDomainEventNew(int id, const char *name, const unsigned char *uuid, int type, int detail) @@ -1381,6 +1435,9 @@ static int virDomainEventDispatchMatchCallback(virDomainEventPtr event, if (cb->eventID != event->eventID) return 0; + if (cb->filter && !(cb->filter)(cb->conn, event, cb->filter_opaque)) + return 0; + if (cb->dom) { /* Deliberately ignoring 'id' for matching, since that * will cause problems when a domain switches between @@ -1510,6 +1567,7 @@ virDomainEventStateFlush(virDomainEventStatePtr state) * virDomainEventStateRegister: * @conn: connection to associate with callback * @state: domain event state + * @filter: optional ACL filter to limit which events can be sent * @callback: function to remove from event * @opaque: data blob to pass to callback * @freecb: callback to free @opaque @@ -1522,6 +1580,7 @@ virDomainEventStateFlush(virDomainEventStatePtr state) int virDomainEventStateRegister(virConnectPtr conn, virDomainEventStatePtr state, + virDomainObjListFilter filter, virConnectDomainEventCallback callback, void *opaque, virFreeCallback freecb) @@ -1542,7 +1601,8 @@ virDomainEventStateRegister(virConnectPtr conn, } ret = virDomainEventCallbackListAdd(conn, state->callbacks, - callback, opaque, freecb); + filter ? virDomainEventFilter : NULL, + filter, callback, opaque, freecb); if (ret == -1 && state->callbacks->count == 0 && @@ -1561,6 +1621,7 @@ cleanup: * virDomainEventStateRegisterID: * @conn: connection to associate with callback * @state: domain event state + * @filter: optional ACL filter to limit which events can be sent * @eventID: ID of the event type to register for * @cb: function to remove from event * @opaque: data blob to pass to callback @@ -1575,6 +1636,7 @@ cleanup: int virDomainEventStateRegisterID(virConnectPtr conn, virDomainEventStatePtr state, + virDomainObjListFilter filter, virDomainPtr dom, int eventID, virConnectDomainEventGenericCallback cb, @@ -1597,8 +1659,9 @@ virDomainEventStateRegisterID(virConnectPtr conn, goto cleanup; } - ret = virDomainEventCallbackListAddID(conn, state->callbacks, - dom, eventID, cb, opaque, freecb, + ret = virDomainEventCallbackListAddID(conn, state->callbacks, dom, + filter ? virDomainEventFilter : NULL, + filter, eventID, cb, opaque, freecb, callbackID); if (ret == -1 && diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h index f6b957d596..9dc65e22d3 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 * * This library is free software; you can redistribute it and/or @@ -149,19 +149,21 @@ virDomainEventStateQueue(virDomainEventStatePtr state, ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); int virDomainEventStateRegister(virConnectPtr conn, virDomainEventStatePtr 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, virDomainEventStatePtr 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, virDomainEventStatePtr state, diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 0a67ad24f5..431dfa3d89 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -4203,6 +4203,7 @@ libxlConnectDomainEventRegister(virConnectPtr conn, libxlDriverLock(driver); ret = virDomainEventStateRegister(conn, driver->domainEventState, + virConnectDomainEventRegisterCheckACL, callback, opaque, freecb); libxlDriverUnlock(driver); @@ -4880,6 +4881,7 @@ libxlConnectDomainEventRegisterAny(virConnectPtr conn, virDomainPtr dom, int eve libxlDriverLock(driver); 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 ece8230a7f..b458474abc 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -1295,6 +1295,7 @@ lxcConnectDomainEventRegister(virConnectPtr conn, ret = virDomainEventStateRegister(conn, driver->domainEventState, + virConnectDomainEventRegisterCheckACL, callback, opaque, freecb); return ret; @@ -1335,6 +1336,7 @@ lxcConnectDomainEventRegisterAny(virConnectPtr conn, if (virDomainEventStateRegisterID(conn, driver->domainEventState, + virConnectDomainEventRegisterAnyCheckACL, dom, eventID, callback, opaque, freecb, &ret) < 0) ret = -1; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 0170179c2e..c1d6868869 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -9877,6 +9877,7 @@ qemuConnectDomainEventRegister(virConnectPtr conn, if (virDomainEventStateRegister(conn, driver->domainEventState, + virConnectDomainEventRegisterCheckACL, callback, opaque, freecb) < 0) goto cleanup; @@ -9925,6 +9926,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 b3e86e1d5d..18e5273da8 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -4309,7 +4309,7 @@ static int remoteConnectDomainEventRegister(virConnectPtr conn, remoteDriverLock(priv); - if ((count = virDomainEventStateRegister(conn, priv->domainEventState, + if ((count = virDomainEventStateRegister(conn, priv->domainEventState, NULL, callback, opaque, freecb)) < 0) { virReportError(VIR_ERR_RPC, "%s", _("adding cb to list")); goto done; @@ -5095,7 +5095,7 @@ static int remoteConnectDomainEventRegisterAny(virConnectPtr conn, remoteDriverLock(priv); if ((count = virDomainEventStateRegisterID(conn, - priv->domainEventState, + priv->domainEventState, NULL, dom, eventID, callback, opaque, freecb, &callbackID)) < 0) { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 24c3f6c0d7..e64ae40178 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -1952,7 +1952,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. */ @@ -3606,7 +3606,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, @@ -4038,7 +4039,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, diff --git a/src/test/test_driver.c b/src/test/test_driver.c index c2256188df..c8b1282dc9 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -5628,7 +5628,7 @@ testConnectDomainEventRegister(virConnectPtr conn, testDriverLock(driver); ret = virDomainEventStateRegister(conn, - driver->domainEventState, + driver->domainEventState, NULL, callback, opaque, freecb); testDriverUnlock(driver); @@ -5666,7 +5666,7 @@ testConnectDomainEventRegisterAny(virConnectPtr conn, testDriverLock(driver); if (virDomainEventStateRegisterID(conn, - driver->domainEventState, + driver->domainEventState, NULL, dom, eventID, callback, opaque, freecb, &ret) < 0) ret = -1; diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 9ca352f462..6e6761bb9f 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -2618,6 +2618,7 @@ umlConnectDomainEventRegister(virConnectPtr conn, umlDriverLock(driver); ret = virDomainEventStateRegister(conn, driver->domainEventState, + virConnectDomainEventRegisterCheckACL, callback, opaque, freecb); umlDriverUnlock(driver); @@ -2660,6 +2661,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 5b17048417..27f4197e11 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -7265,7 +7265,7 @@ static int 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("virDomainEventStateRegister (ret = %d) (conn: %p, " "callback: %p, opaque: %p, " @@ -7357,7 +7357,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 cb64de65c2..4356280a9e 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -2306,6 +2306,7 @@ xenUnifiedConnectDomainEventRegister(virConnectPtr conn, } ret = virDomainEventStateRegister(conn, priv->domainEvents, + virConnectDomainEventRegisterCheckACL, callback, opaque, freefunc); xenUnifiedUnlock(priv); @@ -2363,6 +2364,7 @@ xenUnifiedConnectDomainEventRegisterAny(virConnectPtr conn, } if (virDomainEventStateRegisterID(conn, priv->domainEvents, + virConnectDomainEventRegisterAnyCheckACL, dom, eventID, callback, opaque, freefunc, &ret) < 0) ret = -1;