873
class DBusObjectWithAnnotations(dbus.service.Object):
874
"""A D-Bus object with annotations.
872
class DBusObjectWithProperties(dbus.service.Object):
873
"""A D-Bus object with properties.
876
Classes inheriting from this can use the dbus_annotations
877
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.
896
896
for name, athing in
897
897
inspect.getmembers(cls, self._is_dbus_thing(thing)))
899
@dbus.service.method(dbus.INTROSPECTABLE_IFACE,
901
path_keyword = 'object_path',
902
connection_keyword = 'connection')
903
def Introspect(self, object_path, connection):
904
"""Overloading of standard D-Bus method.
906
Inserts annotation tags on methods and signals.
908
xmlstring = dbus.service.Object.Introspect(self, object_path,
911
document = xml.dom.minidom.parseString(xmlstring)
913
for if_tag in document.getElementsByTagName("interface"):
914
# Add annotation tags
915
for typ in ("method", "signal"):
916
for tag in if_tag.getElementsByTagName(typ):
918
for name, prop in (self.
919
_get_all_dbus_things(typ)):
920
if (name == tag.getAttribute("name")
921
and prop._dbus_interface
922
== if_tag.getAttribute("name")):
923
annots.update(getattr(
924
prop, "_dbus_annotations", {}))
925
for name, value in annots.items():
926
ann_tag = document.createElement(
928
ann_tag.setAttribute("name", name)
929
ann_tag.setAttribute("value", value)
930
tag.appendChild(ann_tag)
931
# Add interface annotation tags
932
for annotation, value in dict(
933
itertools.chain.from_iterable(
934
annotations().items()
935
for name, annotations
936
in self._get_all_dbus_things("interface")
937
if name == if_tag.getAttribute("name")
939
ann_tag = document.createElement("annotation")
940
ann_tag.setAttribute("name", annotation)
941
ann_tag.setAttribute("value", value)
942
if_tag.appendChild(ann_tag)
943
# Fix argument name for the Introspect method itself
944
if (if_tag.getAttribute("name")
945
== dbus.INTROSPECTABLE_IFACE):
946
for cn in if_tag.getElementsByTagName("method"):
947
if cn.getAttribute("name") == "Introspect":
948
for arg in cn.getElementsByTagName("arg"):
949
if (arg.getAttribute("direction")
951
arg.setAttribute("name",
953
xmlstring = document.toxml("utf-8")
955
except (AttributeError, xml.dom.DOMException,
956
xml.parsers.expat.ExpatError) as error:
957
logger.error("Failed to override Introspection method",
962
class DBusObjectWithProperties(DBusObjectWithAnnotations):
963
"""A D-Bus object with properties.
965
Classes inheriting from this can use the dbus_service_property
966
decorator to expose methods as D-Bus properties. It exposes the
967
standard Get(), Set(), and GetAll() methods on the D-Bus.
970
899
def _get_dbus_property(self, interface_name, property_name):
971
900
"""Returns a bound method if one exists which is a D-Bus
972
901
property with the specified name and interface.
982
911
raise DBusPropertyNotFound("{}:{}.{}".format(
983
912
self.dbus_object_path, interface_name, property_name))
986
def _get_all_interface_names(cls):
987
"""Get a sequence of all interfaces supported by an object"""
988
return (name for name in set(getattr(getattr(x, attr),
989
"_dbus_interface", None)
990
for x in (inspect.getmro(cls))
994
914
@dbus.service.method(dbus.PROPERTIES_IFACE,
995
915
in_signature="ss",
996
916
out_signature="v")
1087
1006
if prop._dbus_interface
1088
1007
== if_tag.getAttribute("name")):
1089
1008
if_tag.appendChild(tag)
1090
# Add annotation tags for properties
1091
for tag in if_tag.getElementsByTagName("property"):
1093
for name, prop in self._get_all_dbus_things(
1095
if (name == tag.getAttribute("name")
1096
and prop._dbus_interface
1097
== if_tag.getAttribute("name")):
1098
annots.update(getattr(
1099
prop, "_dbus_annotations", {}))
1100
for name, value in annots.items():
1101
ann_tag = document.createElement(
1103
ann_tag.setAttribute("name", name)
1104
ann_tag.setAttribute("value", value)
1105
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)
1106
1038
# Add the names to the return values for the
1107
1039
# "org.freedesktop.DBus.Properties" methods
1108
1040
if (if_tag.getAttribute("name")
1126
1058
exc_info=error)
1127
1059
return xmlstring
1130
dbus.OBJECT_MANAGER_IFACE
1131
except AttributeError:
1132
dbus.OBJECT_MANAGER_IFACE = "org.freedesktop.DBus.ObjectManager"
1134
class DBusObjectWithObjectManager(DBusObjectWithAnnotations):
1135
"""A D-Bus object with an ObjectManager.
1137
Classes inheriting from this exposes the standard
1138
GetManagedObjects call and the InterfacesAdded and
1139
InterfacesRemoved signals on the standard
1140
"org.freedesktop.DBus.ObjectManager" interface.
1142
Note: No signals are sent automatically; they must be sent
1145
@dbus.service.method(dbus.OBJECT_MANAGER_IFACE,
1146
out_signature = "a{oa{sa{sv}}}")
1147
def GetManagedObjects(self):
1148
"""This function must be overridden"""
1149
raise NotImplementedError()
1151
@dbus.service.signal(dbus.OBJECT_MANAGER_IFACE,
1152
signature = "oa{sa{sv}}")
1153
def InterfacesAdded(self, object_path, interfaces_and_properties):
1156
@dbus.service.signal(dbus.OBJECT_MANAGER_IFACE, signature = "oas")
1157
def InterfacesRemoved(self, object_path, interfaces):
1160
@dbus.service.method(dbus.INTROSPECTABLE_IFACE,
1161
out_signature = "s",
1162
path_keyword = 'object_path',
1163
connection_keyword = 'connection')
1164
def Introspect(self, object_path, connection):
1165
"""Overloading of standard D-Bus method.
1167
Override return argument name of GetManagedObjects to be
1168
"objpath_interfaces_and_properties"
1170
xmlstring = DBusObjectWithAnnotations.Introspect(self,
1174
document = xml.dom.minidom.parseString(xmlstring)
1176
for if_tag in document.getElementsByTagName("interface"):
1177
# Fix argument name for the GetManagedObjects method
1178
if (if_tag.getAttribute("name")
1179
== dbus.OBJECT_MANAGER_IFACE):
1180
for cn in if_tag.getElementsByTagName("method"):
1181
if (cn.getAttribute("name")
1182
== "GetManagedObjects"):
1183
for arg in cn.getElementsByTagName("arg"):
1184
if (arg.getAttribute("direction")
1188
"objpath_interfaces"
1190
xmlstring = document.toxml("utf-8")
1192
except (AttributeError, xml.dom.DOMException,
1193
xml.parsers.expat.ExpatError) as error:
1194
logger.error("Failed to override Introspection method",
1198
1062
def datetime_to_dbus(dt, variant_level=0):
1199
1063
"""Convert a UTC datetime.datetime() to a D-Bus type."""
1290
1154
func1 and func2 to the "call_both" function
1291
1155
outside of its arguments"""
1293
@functools.wraps(func2)
1294
1157
def call_both(*args, **kwargs):
1295
1158
"""This function will emit two D-Bus
1296
1159
signals by calling func1 and func2"""
1297
1160
func1(*args, **kwargs)
1298
1161
func2(*args, **kwargs)
1299
# Make wrapper function look like a D-Bus signal
1300
for name, attr in inspect.getmembers(func2):
1301
if name.startswith("_dbus_"):
1302
setattr(call_both, name, attr)
1304
1163
return call_both
1305
1164
# Create the "call_both" function and add it to
1517
1376
if exitstatus >= 0:
1518
1377
# Emit D-Bus signal
1519
1378
self.CheckerCompleted(dbus.Int16(exitstatus),
1520
# This is specific to GNU libC
1521
dbus.Int64(exitstatus << 8),
1522
1380
dbus.String(command))
1524
1382
# Emit D-Bus signal
1525
1383
self.CheckerCompleted(dbus.Int16(-1),
1527
# This is specific to GNU libC
1529
| self.last_checker_signal),
1385
self.last_checker_signal),
1530
1386
dbus.String(command))
2915
@dbus_annotations({"org.freedesktop.DBus.Deprecated":
2917
2772
@dbus.service.signal(_interface, signature="os")
2918
2773
def ClientRemoved(self, objpath, name):
2922
@dbus_annotations({"org.freedesktop.DBus.Deprecated":
2924
2777
@dbus.service.method(_interface, out_signature="ao")
2925
2778
def GetAllClients(self):
2927
2780
return dbus.Array(c.dbus_object_path for c in
2928
2781
tcp_server.clients.itervalues())
2930
@dbus_annotations({"org.freedesktop.DBus.Deprecated":
2932
2783
@dbus.service.method(_interface,
2933
2784
out_signature="a{oa{sv}}")
2934
2785
def GetAllClientsWithProperties(self):
2936
2787
return dbus.Dictionary(
2937
{ c.dbus_object_path: c.GetAll(
2938
"se.recompile.Mandos.Client")
2788
{ c.dbus_object_path: c.GetAll("")
2939
2789
for c in tcp_server.clients.itervalues() },
2940
2790
signature="oa{sv}")
2946
2796
if c.dbus_object_path == object_path:
2947
2797
del tcp_server.clients[c.name]
2948
2798
c.remove_from_connection()
2949
# Don't signal the disabling
2799
# Don't signal anything except ClientRemoved
2950
2800
c.disable(quiet=True)
2951
# Emit D-Bus signal for removal
2952
self.client_removed_signal(c)
2802
self.ClientRemoved(object_path, c.name)
2954
2804
raise KeyError(object_path)
2958
@dbus.service.method(dbus.OBJECT_MANAGER_IFACE,
2959
out_signature = "a{oa{sa{sv}}}")
2960
def GetManagedObjects(self):
2962
return dbus.Dictionary(
2963
{ client.dbus_object_path:
2965
{ interface: client.GetAll(interface)
2967
client._get_all_interface_names()})
2968
for client in tcp_server.clients.values()})
2970
def client_added_signal(self, client):
2971
"""Send the new standard signal and the old signal"""
2973
# New standard signal
2974
self.InterfacesAdded(
2975
client.dbus_object_path,
2977
{ interface: client.GetAll(interface)
2979
client._get_all_interface_names()}))
2981
self.ClientAdded(client.dbus_object_path)
2983
def client_removed_signal(self, client):
2984
"""Send the new standard signal and the old signal"""
2986
# New standard signal
2987
self.InterfacesRemoved(
2988
client.dbus_object_path,
2989
client._get_all_interface_names())
2991
self.ClientRemoved(client.dbus_object_path,
2994
2808
mandos_dbus_service = MandosDBusService()
3060
2874
name, client = tcp_server.clients.popitem()
3062
2876
client.remove_from_connection()
3063
# Don't signal the disabling
2877
# Don't signal anything except ClientRemoved
3064
2878
client.disable(quiet=True)
3065
# Emit D-Bus signal for removal
3067
mandos_dbus_service.client_removed_signal(client)
2881
mandos_dbus_service.ClientRemoved(
2882
client.dbus_object_path, client.name)
3068
2883
client_settings.clear()
3070
2885
atexit.register(cleanup)
3072
2887
for client in tcp_server.clients.itervalues():
3074
# Emit D-Bus signal for adding
3075
mandos_dbus_service.client_added_signal(client)
2890
mandos_dbus_service.ClientAdded(client.dbus_object_path)
3076
2891
# Need to initiate checking of clients
3077
2892
if client.enabled:
3078
2893
client.init_checker()