395
395
logger.error(bad_states[state] + ": %r", error)
397
397
elif state == avahi.SERVER_RUNNING:
400
except dbus.exceptions.DBusException as error:
401
if (error.get_dbus_name()
402
== "org.freedesktop.Avahi.CollisionError"):
403
logger.info("Local Zeroconf service name"
405
return self.rename(remove=False)
407
logger.critical("D-Bus Exception", exc_info=error)
400
411
if error is None:
401
412
logger.debug("Unknown state: %r", state)
861
class DBusObjectWithProperties(dbus.service.Object):
862
"""A D-Bus object with properties.
874
class DBusObjectWithAnnotations(dbus.service.Object):
875
"""A D-Bus object with annotations.
864
Classes inheriting from this can use the dbus_service_property
865
decorator to expose methods as D-Bus properties. It exposes the
866
standard Get(), Set(), and GetAll() methods on the D-Bus.
877
Classes inheriting from this can use the dbus_annotations
878
decorator to add annotations to methods or signals.
885
897
for name, athing in
886
898
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.
888
971
def _get_dbus_property(self, interface_name, property_name):
889
972
"""Returns a bound method if one exists which is a D-Bus
890
973
property with the specified name and interface.
900
983
raise DBusPropertyNotFound("{}:{}.{}".format(
901
984
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))
903
995
@dbus.service.method(dbus.PROPERTIES_IFACE,
904
996
in_signature="ss",
905
997
out_signature="v")
995
1088
if prop._dbus_interface
996
1089
== if_tag.getAttribute("name")):
997
1090
if_tag.appendChild(tag)
998
# Add annotation tags
999
for typ in ("method", "signal", "property"):
1000
for tag in if_tag.getElementsByTagName(typ):
1002
for name, prop in (self.
1003
_get_all_dbus_things(typ)):
1004
if (name == tag.getAttribute("name")
1005
and prop._dbus_interface
1006
== if_tag.getAttribute("name")):
1007
annots.update(getattr(
1008
prop, "_dbus_annotations", {}))
1009
for name, value in annots.items():
1010
ann_tag = document.createElement(
1012
ann_tag.setAttribute("name", name)
1013
ann_tag.setAttribute("value", value)
1014
tag.appendChild(ann_tag)
1015
# Add interface annotation tags
1016
for annotation, value in dict(
1017
itertools.chain.from_iterable(
1018
annotations().items()
1019
for name, annotations
1020
in self._get_all_dbus_things("interface")
1021
if name == if_tag.getAttribute("name")
1023
ann_tag = document.createElement("annotation")
1024
ann_tag.setAttribute("name", annotation)
1025
ann_tag.setAttribute("value", value)
1026
if_tag.appendChild(ann_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)
1027
1107
# Add the names to the return values for the
1028
1108
# "org.freedesktop.DBus.Properties" methods
1029
1109
if (if_tag.getAttribute("name")
1047
1127
exc_info=error)
1048
1128
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",
1051
1199
def datetime_to_dbus(dt, variant_level=0):
1052
1200
"""Convert a UTC datetime.datetime() to a D-Bus type."""
1143
1291
func1 and func2 to the "call_both" function
1144
1292
outside of its arguments"""
1294
@functools.wraps(func2)
1146
1295
def call_both(*args, **kwargs):
1147
1296
"""This function will emit two D-Bus
1148
1297
signals by calling func1 and func2"""
1149
1298
func1(*args, **kwargs)
1150
1299
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)
1152
1305
return call_both
1153
1306
# Create the "call_both" function and add it to
1365
1518
if exitstatus >= 0:
1366
1519
# Emit D-Bus signal
1367
1520
self.CheckerCompleted(dbus.Int16(exitstatus),
1521
# This is specific to GNU libC
1522
dbus.Int64(exitstatus << 8),
1369
1523
dbus.String(command))
1371
1525
# Emit D-Bus signal
1372
1526
self.CheckerCompleted(dbus.Int16(-1),
1374
self.last_checker_signal),
1528
# This is specific to GNU libC
1530
| self.last_checker_signal),
1375
1531
dbus.String(command))
1513
1673
self.approval_duration = datetime.timedelta(0, 0, 0, value)
1515
1675
# Name - property
1677
{"org.freedesktop.DBus.Property.EmitsChangedSignal": "const"})
1516
1678
@dbus_service_property(_interface, signature="s", access="read")
1517
1679
def Name_dbus_property(self):
1518
1680
return dbus.String(self.name)
1520
1682
# Fingerprint - property
1684
{"org.freedesktop.DBus.Property.EmitsChangedSignal": "const"})
1521
1685
@dbus_service_property(_interface, signature="s", access="read")
1522
1686
def Fingerprint_dbus_property(self):
1523
1687
return dbus.String(self.fingerprint)
1652
1818
self.stop_checker()
1654
1820
# ObjectPath - property
1822
{"org.freedesktop.DBus.Property.EmitsChangedSignal": "const",
1823
"org.freedesktop.DBus.Deprecated": "true"})
1655
1824
@dbus_service_property(_interface, signature="o", access="read")
1656
1825
def ObjectPath_dbus_property(self):
1657
1826
return self.dbus_object_path # is already a dbus.ObjectPath
1659
1828
# Secret = property
1830
{"org.freedesktop.DBus.Property.EmitsChangedSignal":
1660
1832
@dbus_service_property(_interface,
1661
1833
signature="ay",
1662
1834
access="write",
2916
@dbus_annotations({"org.freedesktop.DBus.Deprecated":
2750
2918
@dbus.service.signal(_interface, signature="os")
2751
2919
def ClientRemoved(self, objpath, name):
2923
@dbus_annotations({"org.freedesktop.DBus.Deprecated":
2755
2925
@dbus.service.method(_interface, out_signature="ao")
2756
2926
def GetAllClients(self):
2758
2928
return dbus.Array(c.dbus_object_path for c in
2759
2929
tcp_server.clients.itervalues())
2931
@dbus_annotations({"org.freedesktop.DBus.Deprecated":
2761
2933
@dbus.service.method(_interface,
2762
2934
out_signature="a{oa{sv}}")
2763
2935
def GetAllClientsWithProperties(self):
2765
2937
return dbus.Dictionary(
2766
{ c.dbus_object_path: c.GetAll("")
2938
{ c.dbus_object_path: c.GetAll(
2939
"se.recompile.Mandos.Client")
2767
2940
for c in tcp_server.clients.itervalues() },
2768
2941
signature="oa{sv}")
2774
2947
if c.dbus_object_path == object_path:
2775
2948
del tcp_server.clients[c.name]
2776
2949
c.remove_from_connection()
2777
# Don't signal anything except ClientRemoved
2950
# Don't signal the disabling
2778
2951
c.disable(quiet=True)
2780
self.ClientRemoved(object_path, c.name)
2952
# Emit D-Bus signal for removal
2953
self.client_removed_signal(c)
2782
2955
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,
2786
2995
mandos_dbus_service = MandosDBusService()
2852
3061
name, client = tcp_server.clients.popitem()
2854
3063
client.remove_from_connection()
2855
# Don't signal anything except ClientRemoved
3064
# Don't signal the disabling
2856
3065
client.disable(quiet=True)
2859
mandos_dbus_service.ClientRemoved(
2860
client.dbus_object_path, client.name)
3066
# Emit D-Bus signal for removal
3067
mandos_dbus_service.client_removed_signal(client)
2861
3068
client_settings.clear()
2863
3070
atexit.register(cleanup)
2865
3072
for client in tcp_server.clients.itervalues():
2868
mandos_dbus_service.ClientAdded(client.dbus_object_path)
3074
# Emit D-Bus signal for adding
3075
mandos_dbus_service.client_added_signal(client)
2869
3076
# Need to initiate checking of clients
2870
3077
if client.enabled:
2871
3078
client.init_checker()