874
class DBusObjectWithAnnotations(dbus.service.Object):
875
"""A D-Bus object with annotations.
872
class DBusObjectWithProperties(dbus.service.Object):
873
"""A D-Bus object with properties.
877
Classes inheriting from this can use the dbus_annotations
878
decorator to add annotations to methods or signals.
875
Classes inheriting from this can use the dbus_service_property
876
decorator to expose methods as D-Bus properties. It exposes the
877
standard Get(), Set(), and GetAll() methods on the D-Bus.
897
896
for name, athing in
898
897
inspect.getmembers(cls, self._is_dbus_thing(thing)))
900
@dbus.service.method(dbus.INTROSPECTABLE_IFACE,
902
path_keyword = 'object_path',
903
connection_keyword = 'connection')
904
def Introspect(self, object_path, connection):
905
"""Overloading of standard D-Bus method.
907
Inserts annotation tags on methods and signals.
909
xmlstring = dbus.service.Object.Introspect(self, object_path,
912
document = xml.dom.minidom.parseString(xmlstring)
914
for if_tag in document.getElementsByTagName("interface"):
915
# Add annotation tags
916
for typ in ("method", "signal"):
917
for tag in if_tag.getElementsByTagName(typ):
919
for name, prop in (self.
920
_get_all_dbus_things(typ)):
921
if (name == tag.getAttribute("name")
922
and prop._dbus_interface
923
== if_tag.getAttribute("name")):
924
annots.update(getattr(
925
prop, "_dbus_annotations", {}))
926
for name, value in annots.items():
927
ann_tag = document.createElement(
929
ann_tag.setAttribute("name", name)
930
ann_tag.setAttribute("value", value)
931
tag.appendChild(ann_tag)
932
# Add interface annotation tags
933
for annotation, value in dict(
934
itertools.chain.from_iterable(
935
annotations().items()
936
for name, annotations
937
in self._get_all_dbus_things("interface")
938
if name == if_tag.getAttribute("name")
940
ann_tag = document.createElement("annotation")
941
ann_tag.setAttribute("name", annotation)
942
ann_tag.setAttribute("value", value)
943
if_tag.appendChild(ann_tag)
944
# Fix argument name for the Introspect method itself
945
if (if_tag.getAttribute("name")
946
== dbus.INTROSPECTABLE_IFACE):
947
for cn in if_tag.getElementsByTagName("method"):
948
if cn.getAttribute("name") == "Introspect":
949
for arg in cn.getElementsByTagName("arg"):
950
if (arg.getAttribute("direction")
952
arg.setAttribute("name",
954
xmlstring = document.toxml("utf-8")
956
except (AttributeError, xml.dom.DOMException,
957
xml.parsers.expat.ExpatError) as error:
958
logger.error("Failed to override Introspection method",
963
class DBusObjectWithProperties(DBusObjectWithAnnotations):
964
"""A D-Bus object with properties.
966
Classes inheriting from this can use the dbus_service_property
967
decorator to expose methods as D-Bus properties. It exposes the
968
standard Get(), Set(), and GetAll() methods on the D-Bus.
971
899
def _get_dbus_property(self, interface_name, property_name):
972
900
"""Returns a bound method if one exists which is a D-Bus
973
901
property with the specified name and interface.
983
911
raise DBusPropertyNotFound("{}:{}.{}".format(
984
912
self.dbus_object_path, interface_name, property_name))
987
def _get_all_interface_names(cls):
988
"""Get a sequence of all interfaces supported by an object"""
989
return (name for name in set(getattr(getattr(x, attr),
990
"_dbus_interface", None)
991
for x in (inspect.getmro(cls))
995
914
@dbus.service.method(dbus.PROPERTIES_IFACE,
996
915
in_signature="ss",
997
916
out_signature="v")
1088
1006
if prop._dbus_interface
1089
1007
== if_tag.getAttribute("name")):
1090
1008
if_tag.appendChild(tag)
1091
# Add annotation tags for properties
1092
for tag in if_tag.getElementsByTagName("property"):
1094
for name, prop in self._get_all_dbus_things(
1096
if (name == tag.getAttribute("name")
1097
and prop._dbus_interface
1098
== if_tag.getAttribute("name")):
1099
annots.update(getattr(
1100
prop, "_dbus_annotations", {}))
1101
for name, value in annots.items():
1102
ann_tag = document.createElement(
1104
ann_tag.setAttribute("name", name)
1105
ann_tag.setAttribute("value", value)
1106
tag.appendChild(ann_tag)
1009
# Add annotation tags
1010
for typ in ("method", "signal", "property"):
1011
for tag in if_tag.getElementsByTagName(typ):
1013
for name, prop in (self.
1014
_get_all_dbus_things(typ)):
1015
if (name == tag.getAttribute("name")
1016
and prop._dbus_interface
1017
== if_tag.getAttribute("name")):
1018
annots.update(getattr(
1019
prop, "_dbus_annotations", {}))
1020
for name, value in annots.items():
1021
ann_tag = document.createElement(
1023
ann_tag.setAttribute("name", name)
1024
ann_tag.setAttribute("value", value)
1025
tag.appendChild(ann_tag)
1026
# Add interface annotation tags
1027
for annotation, value in dict(
1028
itertools.chain.from_iterable(
1029
annotations().items()
1030
for name, annotations
1031
in self._get_all_dbus_things("interface")
1032
if name == if_tag.getAttribute("name")
1034
ann_tag = document.createElement("annotation")
1035
ann_tag.setAttribute("name", annotation)
1036
ann_tag.setAttribute("value", value)
1037
if_tag.appendChild(ann_tag)
1107
1038
# Add the names to the return values for the
1108
1039
# "org.freedesktop.DBus.Properties" methods
1109
1040
if (if_tag.getAttribute("name")
1127
1058
exc_info=error)
1128
1059
return xmlstring
1131
dbus.OBJECT_MANAGER_IFACE
1132
except AttributeError:
1133
dbus.OBJECT_MANAGER_IFACE = "org.freedesktop.DBus.ObjectManager"
1135
class DBusObjectWithObjectManager(DBusObjectWithAnnotations):
1136
"""A D-Bus object with an ObjectManager.
1138
Classes inheriting from this exposes the standard
1139
GetManagedObjects call and the InterfacesAdded and
1140
InterfacesRemoved signals on the standard
1141
"org.freedesktop.DBus.ObjectManager" interface.
1143
Note: No signals are sent automatically; they must be sent
1146
@dbus.service.method(dbus.OBJECT_MANAGER_IFACE,
1147
out_signature = "a{oa{sa{sv}}}")
1148
def GetManagedObjects(self):
1149
"""This function must be overridden"""
1150
raise NotImplementedError()
1152
@dbus.service.signal(dbus.OBJECT_MANAGER_IFACE,
1153
signature = "oa{sa{sv}}")
1154
def InterfacesAdded(self, object_path, interfaces_and_properties):
1157
@dbus.service.signal(dbus.OBJECT_MANAGER_IFACE, signature = "oas")
1158
def InterfacesRemoved(self, object_path, interfaces):
1161
@dbus.service.method(dbus.INTROSPECTABLE_IFACE,
1162
out_signature = "s",
1163
path_keyword = 'object_path',
1164
connection_keyword = 'connection')
1165
def Introspect(self, object_path, connection):
1166
"""Overloading of standard D-Bus method.
1168
Override return argument name of GetManagedObjects to be
1169
"objpath_interfaces_and_properties"
1171
xmlstring = DBusObjectWithAnnotations.Introspect(self,
1175
document = xml.dom.minidom.parseString(xmlstring)
1177
for if_tag in document.getElementsByTagName("interface"):
1178
# Fix argument name for the GetManagedObjects method
1179
if (if_tag.getAttribute("name")
1180
== dbus.OBJECT_MANAGER_IFACE):
1181
for cn in if_tag.getElementsByTagName("method"):
1182
if (cn.getAttribute("name")
1183
== "GetManagedObjects"):
1184
for arg in cn.getElementsByTagName("arg"):
1185
if (arg.getAttribute("direction")
1189
"objpath_interfaces"
1191
xmlstring = document.toxml("utf-8")
1193
except (AttributeError, xml.dom.DOMException,
1194
xml.parsers.expat.ExpatError) as error:
1195
logger.error("Failed to override Introspection method",
1199
1062
def datetime_to_dbus(dt, variant_level=0):
1200
1063
"""Convert a UTC datetime.datetime() to a D-Bus type."""
1291
1154
func1 and func2 to the "call_both" function
1292
1155
outside of its arguments"""
1294
@functools.wraps(func2)
1295
1157
def call_both(*args, **kwargs):
1296
1158
"""This function will emit two D-Bus
1297
1159
signals by calling func1 and func2"""
1298
1160
func1(*args, **kwargs)
1299
1161
func2(*args, **kwargs)
1300
# Make wrapper function look like a D-Bus signal
1301
for name, attr in inspect.getmembers(func2):
1302
if name.startswith("_dbus_"):
1303
setattr(call_both, name, attr)
1305
1163
return call_both
1306
1164
# Create the "call_both" function and add it to
1518
1376
if exitstatus >= 0:
1519
1377
# Emit D-Bus signal
1520
1378
self.CheckerCompleted(dbus.Int16(exitstatus),
1521
# This is specific to GNU libC
1522
dbus.Int64(exitstatus << 8),
1523
1380
dbus.String(command))
1525
1382
# Emit D-Bus signal
1526
1383
self.CheckerCompleted(dbus.Int16(-1),
1528
# This is specific to GNU libC
1530
| self.last_checker_signal),
1385
self.last_checker_signal),
1531
1386
dbus.String(command))
1673
1524
self.approval_duration = datetime.timedelta(0, 0, 0, value)
1675
1526
# Name - property
1677
{"org.freedesktop.DBus.Property.EmitsChangedSignal": "const"})
1678
1527
@dbus_service_property(_interface, signature="s", access="read")
1679
1528
def Name_dbus_property(self):
1680
1529
return dbus.String(self.name)
1682
1531
# Fingerprint - property
1684
{"org.freedesktop.DBus.Property.EmitsChangedSignal": "const"})
1685
1532
@dbus_service_property(_interface, signature="s", access="read")
1686
1533
def Fingerprint_dbus_property(self):
1687
1534
return dbus.String(self.fingerprint)
1818
1663
self.stop_checker()
1820
1665
# ObjectPath - property
1822
{"org.freedesktop.DBus.Property.EmitsChangedSignal": "const",
1823
"org.freedesktop.DBus.Deprecated": "true"})
1824
1666
@dbus_service_property(_interface, signature="o", access="read")
1825
1667
def ObjectPath_dbus_property(self):
1826
1668
return self.dbus_object_path # is already a dbus.ObjectPath
1828
1670
# Secret = property
1830
{"org.freedesktop.DBus.Property.EmitsChangedSignal":
1832
1671
@dbus_service_property(_interface,
1833
1672
signature="ay",
1834
1673
access="write",
2916
@dbus_annotations({"org.freedesktop.DBus.Deprecated":
2918
2761
@dbus.service.signal(_interface, signature="os")
2919
2762
def ClientRemoved(self, objpath, name):
2923
@dbus_annotations({"org.freedesktop.DBus.Deprecated":
2925
2766
@dbus.service.method(_interface, out_signature="ao")
2926
2767
def GetAllClients(self):
2928
2769
return dbus.Array(c.dbus_object_path for c in
2929
2770
tcp_server.clients.itervalues())
2931
@dbus_annotations({"org.freedesktop.DBus.Deprecated":
2933
2772
@dbus.service.method(_interface,
2934
2773
out_signature="a{oa{sv}}")
2935
2774
def GetAllClientsWithProperties(self):
2937
2776
return dbus.Dictionary(
2938
{ c.dbus_object_path: c.GetAll(
2939
"se.recompile.Mandos.Client")
2777
{ c.dbus_object_path: c.GetAll("")
2940
2778
for c in tcp_server.clients.itervalues() },
2941
2779
signature="oa{sv}")
2947
2785
if c.dbus_object_path == object_path:
2948
2786
del tcp_server.clients[c.name]
2949
2787
c.remove_from_connection()
2950
# Don't signal the disabling
2788
# Don't signal anything except ClientRemoved
2951
2789
c.disable(quiet=True)
2952
# Emit D-Bus signal for removal
2953
self.client_removed_signal(c)
2791
self.ClientRemoved(object_path, c.name)
2955
2793
raise KeyError(object_path)
2959
@dbus.service.method(dbus.OBJECT_MANAGER_IFACE,
2960
out_signature = "a{oa{sa{sv}}}")
2961
def GetManagedObjects(self):
2963
return dbus.Dictionary(
2964
{ client.dbus_object_path:
2966
{ interface: client.GetAll(interface)
2968
client._get_all_interface_names()})
2969
for client in tcp_server.clients.values()})
2971
def client_added_signal(self, client):
2972
"""Send the new standard signal and the old signal"""
2974
# New standard signal
2975
self.InterfacesAdded(
2976
client.dbus_object_path,
2978
{ interface: client.GetAll(interface)
2980
client._get_all_interface_names()}))
2982
self.ClientAdded(client.dbus_object_path)
2984
def client_removed_signal(self, client):
2985
"""Send the new standard signal and the old signal"""
2987
# New standard signal
2988
self.InterfacesRemoved(
2989
client.dbus_object_path,
2990
client._get_all_interface_names())
2992
self.ClientRemoved(client.dbus_object_path,
2995
2797
mandos_dbus_service = MandosDBusService()
3061
2863
name, client = tcp_server.clients.popitem()
3063
2865
client.remove_from_connection()
3064
# Don't signal the disabling
2866
# Don't signal anything except ClientRemoved
3065
2867
client.disable(quiet=True)
3066
# Emit D-Bus signal for removal
3067
mandos_dbus_service.client_removed_signal(client)
2870
mandos_dbus_service.ClientRemoved(
2871
client.dbus_object_path, client.name)
3068
2872
client_settings.clear()
3070
2874
atexit.register(cleanup)
3072
2876
for client in tcp_server.clients.itervalues():
3074
# Emit D-Bus signal for adding
3075
mandos_dbus_service.client_added_signal(client)
2879
mandos_dbus_service.ClientAdded(client.dbus_object_path)
3076
2880
# Need to initiate checking of clients
3077
2881
if client.enabled:
3078
2882
client.init_checker()