diff --git a/qubes/mgmt.py b/qubes/mgmt.py index 65b486e9..8a9a76b5 100644 --- a/qubes/mgmt.py +++ b/qubes/mgmt.py @@ -179,6 +179,34 @@ class AbstractQubesMgmt(object): self.fire_event_for_permission(**kwargs)) +class QubesMgmtEventsDispatcher(object): + def __init__(self, filters, send_event): + self.filters = filters + self.send_event = send_event + + def vm_handler(self, subject, event, **kwargs): + if event.startswith('mgmt-permission:'): + return + if not list(apply_filters([(subject, event, kwargs)], + self.filters)): + return + self.send_event(subject, event, **kwargs) + + def app_handler(self, subject, event, **kwargs): + if not list(apply_filters([(subject, event, kwargs)], + self.filters)): + return + self.send_event(subject, event, **kwargs) + + def on_domain_add(self, subject, event, vm): + # pylint: disable=unused-argument + vm.add_handler('*', self.vm_handler) + + def on_domain_delete(self, subject, event, vm): + # pylint: disable=unused-argument + vm.remove_handler('*', self.vm_handler) + + class QubesMgmt(AbstractQubesMgmt): '''Implementation of Qubes Management API calls @@ -590,19 +618,15 @@ class QubesMgmt(AbstractQubesMgmt): # cache event filters, to not call an event each time an event arrives event_filters = self.fire_event_for_permission() - def handler(subject, event, **kwargs): - if self.dest.name != 'dom0' and subject != self.dest: - return - if event.startswith('mgmt-permission:'): - return - if not list(apply_filters([(subject, event, kwargs)], - event_filters)): - return - self.send_event(subject, event, **kwargs) - + dispatcher = QubesMgmtEventsDispatcher(event_filters, self.send_event) if self.dest.name == 'dom0': - type(self.app).add_handler('*', handler) - qubes.vm.BaseVM.add_handler('*', handler) + self.app.add_handler('*', dispatcher.app_handler) + self.app.add_handler('domain-add', dispatcher.on_domain_add) + self.app.add_handler('domain-delete', dispatcher.on_domain_delete) + for vm in self.app.domains: + vm.add_handler('*', dispatcher.vm_handler) + else: + self.dest.add_handler('*', dispatcher.vm_handler) # send artificial event as a confirmation that connection is established self.send_event(self.app, 'connection-established') @@ -614,8 +638,14 @@ class QubesMgmt(AbstractQubesMgmt): pass if self.dest.name == 'dom0': - type(self.app).remove_handler('*', handler) - qubes.vm.BaseVM.remove_handler('*', handler) + self.app.remove_handler('*', dispatcher.app_handler) + self.app.remove_handler('domain-add', dispatcher.on_domain_add) + self.app.remove_handler('domain-delete', + dispatcher.on_domain_delete) + for vm in self.app.domains: + vm.remove_handler('*', dispatcher.vm_handler) + else: + self.dest.remove_handler('*', dispatcher.vm_handler) @api('mgmt.vm.feature.List', no_payload=True) @asyncio.coroutine