385
416
follow_name_owner_changes=True),
386
417
avahi.DBUS_INTERFACE_SERVER)
387
418
self.server.connect_to_signal("StateChanged",
388
self.server_state_changed)
419
self.server_state_changed)
389
420
self.server_state_changed(self.server.GetState())
392
423
class AvahiServiceToSyslog(AvahiService):
424
def rename(self, *args, **kwargs):
394
425
"""Add the new name to the syslog messages"""
395
ret = AvahiService.rename(self)
396
syslogger.setFormatter(logging.Formatter
397
('Mandos ({0}) [%(process)d]:'
398
' %(levelname)s: %(message)s'
426
ret = AvahiService.rename(self, *args, **kwargs)
427
syslogger.setFormatter(logging.Formatter(
428
'Mandos ({}) [%(process)d]: %(levelname)s: %(message)s'
403
def timedelta_to_milliseconds(td):
404
"Convert a datetime.timedelta() to milliseconds"
405
return ((td.days * 24 * 60 * 60 * 1000)
406
+ (td.seconds * 1000)
407
+ (td.microseconds // 1000))
432
# Pretend that we have a GnuTLS module
433
class GnuTLS(object):
434
"""This isn't so much a class as it is a module-like namespace.
435
It is instantiated once, and simulates having a GnuTLS module."""
437
_library = ctypes.cdll.LoadLibrary(
438
ctypes.util.find_library("gnutls"))
439
_need_version = "3.3.0"
441
# Need to use class name "GnuTLS" here, since this method is
442
# called before the assignment to the "gnutls" global variable
444
if GnuTLS.check_version(self._need_version) is None:
445
raise GnuTLS.Error("Needs GnuTLS {} or later"
446
.format(self._need_version))
448
# Unless otherwise indicated, the constants and types below are
449
# all from the gnutls/gnutls.h C header file.
457
E_NO_CERTIFICATE_FOUND = -49
458
OPENPGP_FMT_RAW = 0 # gnutls/openpgp.h
461
class session_int(ctypes.Structure):
463
session_t = ctypes.POINTER(session_int)
464
class certificate_credentials_st(ctypes.Structure):
466
certificate_credentials_t = ctypes.POINTER(
467
certificate_credentials_st)
468
certificate_type_t = ctypes.c_int
469
class datum_t(ctypes.Structure):
470
_fields_ = [('data', ctypes.POINTER(ctypes.c_ubyte)),
471
('size', ctypes.c_uint)]
472
class openpgp_crt_int(ctypes.Structure):
474
openpgp_crt_t = ctypes.POINTER(openpgp_crt_int)
475
openpgp_crt_fmt_t = ctypes.c_int # gnutls/openpgp.h
476
log_func = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p)
477
credentials_type_t = ctypes.c_int #
478
transport_ptr_t = ctypes.c_void_p
479
close_request_t = ctypes.c_int
482
class Error(Exception):
483
# We need to use the class name "GnuTLS" here, since this
484
# exception might be raised from within GnuTLS.__init__,
485
# which is called before the assignment to the "gnutls"
486
# global variable happens.
487
def __init__(self, message = None, code = None, args=()):
488
# Default usage is by a message string, but if a return
489
# code is passed, convert it to a string with
491
if message is None and code is not None:
492
message = GnuTLS.strerror(code)
493
return super(GnuTLS.Error, self).__init__(
496
class CertificateSecurityError(Error):
500
class Credentials(object):
502
self._c_object = gnutls.certificate_credentials_t()
503
gnutls.certificate_allocate_credentials(
504
ctypes.byref(self._c_object))
505
self.type = gnutls.CRD_CERTIFICATE
508
gnutls.certificate_free_credentials(self._c_object)
510
class ClientSession(object):
511
def __init__(self, socket, credentials = None):
512
self._c_object = gnutls.session_t()
513
gnutls.init(ctypes.byref(self._c_object), gnutls.CLIENT)
514
gnutls.set_default_priority(self._c_object)
515
gnutls.transport_set_ptr(self._c_object, socket.fileno())
516
gnutls.handshake_set_private_extensions(self._c_object,
519
if credentials is None:
520
credentials = gnutls.Credentials()
521
gnutls.credentials_set(self._c_object, credentials.type,
522
ctypes.cast(credentials._c_object,
524
self.credentials = credentials
527
gnutls.deinit(self._c_object)
530
return gnutls.handshake(self._c_object)
532
def send(self, data):
536
return gnutls.record_send(self._c_object, data, len(data))
539
return gnutls.bye(self._c_object, gnutls.SHUT_RDWR)
541
# Error handling function
542
def _error_code(result):
543
"""A function to raise exceptions on errors, suitable
544
for the 'restype' attribute on ctypes functions"""
547
if result == gnutls.E_NO_CERTIFICATE_FOUND:
548
raise gnutls.CertificateSecurityError(code = result)
549
raise gnutls.Error(code = result)
551
# Unless otherwise indicated, the function declarations below are
552
# all from the gnutls/gnutls.h C header file.
555
priority_set_direct = _library.gnutls_priority_set_direct
556
priority_set_direct.argtypes = [session_t, ctypes.c_char_p,
557
ctypes.POINTER(ctypes.c_char_p)]
558
priority_set_direct.restype = _error_code
560
init = _library.gnutls_init
561
init.argtypes = [ctypes.POINTER(session_t), ctypes.c_int]
562
init.restype = _error_code
564
set_default_priority = _library.gnutls_set_default_priority
565
set_default_priority.argtypes = [session_t]
566
set_default_priority.restype = _error_code
568
record_send = _library.gnutls_record_send
569
record_send.argtypes = [session_t, ctypes.c_void_p,
571
record_send.restype = ctypes.c_ssize_t
573
certificate_allocate_credentials = (
574
_library.gnutls_certificate_allocate_credentials)
575
certificate_allocate_credentials.argtypes = [
576
ctypes.POINTER(certificate_credentials_t)]
577
certificate_allocate_credentials.restype = _error_code
579
certificate_free_credentials = (
580
_library.gnutls_certificate_free_credentials)
581
certificate_free_credentials.argtypes = [certificate_credentials_t]
582
certificate_free_credentials.restype = None
584
handshake_set_private_extensions = (
585
_library.gnutls_handshake_set_private_extensions)
586
handshake_set_private_extensions.argtypes = [session_t,
588
handshake_set_private_extensions.restype = None
590
credentials_set = _library.gnutls_credentials_set
591
credentials_set.argtypes = [session_t, credentials_type_t,
593
credentials_set.restype = _error_code
595
strerror = _library.gnutls_strerror
596
strerror.argtypes = [ctypes.c_int]
597
strerror.restype = ctypes.c_char_p
599
certificate_type_get = _library.gnutls_certificate_type_get
600
certificate_type_get.argtypes = [session_t]
601
certificate_type_get.restype = _error_code
603
certificate_get_peers = _library.gnutls_certificate_get_peers
604
certificate_get_peers.argtypes = [session_t,
605
ctypes.POINTER(ctypes.c_uint)]
606
certificate_get_peers.restype = ctypes.POINTER(datum_t)
608
global_set_log_level = _library.gnutls_global_set_log_level
609
global_set_log_level.argtypes = [ctypes.c_int]
610
global_set_log_level.restype = None
612
global_set_log_function = _library.gnutls_global_set_log_function
613
global_set_log_function.argtypes = [log_func]
614
global_set_log_function.restype = None
616
deinit = _library.gnutls_deinit
617
deinit.argtypes = [session_t]
618
deinit.restype = None
620
handshake = _library.gnutls_handshake
621
handshake.argtypes = [session_t]
622
handshake.restype = _error_code
624
transport_set_ptr = _library.gnutls_transport_set_ptr
625
transport_set_ptr.argtypes = [session_t, transport_ptr_t]
626
transport_set_ptr.restype = None
628
bye = _library.gnutls_bye
629
bye.argtypes = [session_t, close_request_t]
630
bye.restype = _error_code
632
check_version = _library.gnutls_check_version
633
check_version.argtypes = [ctypes.c_char_p]
634
check_version.restype = ctypes.c_char_p
636
# All the function declarations below are from gnutls/openpgp.h
638
openpgp_crt_init = _library.gnutls_openpgp_crt_init
639
openpgp_crt_init.argtypes = [ctypes.POINTER(openpgp_crt_t)]
640
openpgp_crt_init.restype = _error_code
642
openpgp_crt_import = _library.gnutls_openpgp_crt_import
643
openpgp_crt_import.argtypes = [openpgp_crt_t,
644
ctypes.POINTER(datum_t),
646
openpgp_crt_import.restype = _error_code
648
openpgp_crt_verify_self = _library.gnutls_openpgp_crt_verify_self
649
openpgp_crt_verify_self.argtypes = [openpgp_crt_t, ctypes.c_uint,
650
ctypes.POINTER(ctypes.c_uint)]
651
openpgp_crt_verify_self.restype = _error_code
653
openpgp_crt_deinit = _library.gnutls_openpgp_crt_deinit
654
openpgp_crt_deinit.argtypes = [openpgp_crt_t]
655
openpgp_crt_deinit.restype = None
657
openpgp_crt_get_fingerprint = (
658
_library.gnutls_openpgp_crt_get_fingerprint)
659
openpgp_crt_get_fingerprint.argtypes = [openpgp_crt_t,
663
openpgp_crt_get_fingerprint.restype = _error_code
665
# Remove non-public function
667
# Create the global "gnutls" object, simulating a module
670
def call_pipe(connection, # : multiprocessing.Connection
671
func, *args, **kwargs):
672
"""This function is meant to be called by multiprocessing.Process
674
This function runs func(*args, **kwargs), and writes the resulting
675
return value on the provided multiprocessing.Connection.
677
connection.send(func(*args, **kwargs))
410
680
class Client(object):
411
681
"""A representation of a client host served by this server.
623
878
# and every interval from then on.
624
879
if self.checker_initiator_tag is not None:
625
880
gobject.source_remove(self.checker_initiator_tag)
626
self.checker_initiator_tag = (gobject.timeout_add
627
(self.interval_milliseconds(),
881
self.checker_initiator_tag = gobject.timeout_add(
882
int(self.interval.total_seconds() * 1000),
629
884
# Schedule a disable() when 'timeout' has passed
630
885
if self.disable_initiator_tag is not None:
631
886
gobject.source_remove(self.disable_initiator_tag)
632
self.disable_initiator_tag = (gobject.timeout_add
633
(self.timeout_milliseconds(),
887
self.disable_initiator_tag = gobject.timeout_add(
888
int(self.timeout.total_seconds() * 1000), self.disable)
635
889
# Also start a new checker *right now*.
636
890
self.start_checker()
638
def checker_callback(self, pid, condition, command):
892
def checker_callback(self, source, condition, connection,
639
894
"""The checker has completed, so take appropriate actions."""
640
895
self.checker_callback_tag = None
641
896
self.checker = None
642
if os.WIFEXITED(condition):
643
self.last_checker_status = os.WEXITSTATUS(condition)
897
# Read return code from connection (see call_pipe)
898
returncode = connection.recv()
902
self.last_checker_status = returncode
903
self.last_checker_signal = None
644
904
if self.last_checker_status == 0:
645
905
logger.info("Checker for %(name)s succeeded",
647
907
self.checked_ok()
649
logger.info("Checker for %(name)s failed",
909
logger.info("Checker for %(name)s failed", vars(self))
652
911
self.last_checker_status = -1
912
self.last_checker_signal = -returncode
653
913
logger.warning("Checker for %(name)s crashed?",
656
917
def checked_ok(self):
657
918
"""Assert that the client has been seen, alive and well."""
658
919
self.last_checked_ok = datetime.datetime.utcnow()
659
920
self.last_checker_status = 0
921
self.last_checker_signal = None
660
922
self.bump_timeout()
662
924
def bump_timeout(self, timeout=None):
689
950
# than 'timeout' for the client to be disabled, which is as it
692
# If a checker exists, make sure it is not a zombie
694
pid, status = os.waitpid(self.checker.pid, os.WNOHANG)
695
except AttributeError:
697
except OSError as error:
698
if error.errno != errno.ECHILD:
702
logger.warning("Checker was a zombie")
703
gobject.source_remove(self.checker_callback_tag)
704
self.checker_callback(pid, status,
705
self.current_checker_command)
953
if self.checker is not None and not self.checker.is_alive():
954
logger.warning("Checker was not alive; joining")
706
957
# Start a new checker if needed
707
958
if self.checker is None:
708
959
# Escape attributes for the shell
709
escaped_attrs = dict(
710
(attr, re.escape(unicode(getattr(self, attr))))
712
self.runtime_expansions)
961
attr: re.escape(str(getattr(self, attr)))
962
for attr in self.runtime_expansions }
714
964
command = self.checker_command % escaped_attrs
715
965
except TypeError as error:
716
966
logger.error('Could not format string "%s"',
717
self.checker_command, exc_info=error)
718
return True # Try again later
967
self.checker_command,
969
return True # Try again later
719
970
self.current_checker_command = command
721
logger.info("Starting checker %r for %s",
723
# We don't need to redirect stdout and stderr, since
724
# in normal mode, that is already done by daemon(),
725
# and in debug mode we don't want to. (Stdin is
726
# always replaced by /dev/null.)
727
# The exception is when not debugging but nevertheless
728
# running in the foreground; use the previously
731
if (not self.server_settings["debug"]
732
and self.server_settings["foreground"]):
733
popen_args.update({"stdout": wnull,
735
self.checker = subprocess.Popen(command,
739
except OSError as error:
740
logger.error("Failed to start subprocess",
743
self.checker_callback_tag = (gobject.child_watch_add
745
self.checker_callback,
747
# The checker may have completed before the gobject
748
# watch was added. Check for this.
750
pid, status = os.waitpid(self.checker.pid, os.WNOHANG)
751
except OSError as error:
752
if error.errno == errno.ECHILD:
753
# This should never happen
754
logger.error("Child process vanished",
759
gobject.source_remove(self.checker_callback_tag)
760
self.checker_callback(pid, status, command)
971
logger.info("Starting checker %r for %s", command,
973
# We don't need to redirect stdout and stderr, since
974
# in normal mode, that is already done by daemon(),
975
# and in debug mode we don't want to. (Stdin is
976
# always replaced by /dev/null.)
977
# The exception is when not debugging but nevertheless
978
# running in the foreground; use the previously
980
popen_args = { "close_fds": True,
983
if (not self.server_settings["debug"]
984
and self.server_settings["foreground"]):
985
popen_args.update({"stdout": wnull,
987
pipe = multiprocessing.Pipe(duplex = False)
988
self.checker = multiprocessing.Process(
990
args = (pipe[1], subprocess.call, command),
993
self.checker_callback_tag = gobject.io_add_watch(
994
pipe[0].fileno(), gobject.IO_IN,
995
self.checker_callback, pipe[0], command)
761
996
# Re-run this periodically if run by gobject.timeout_add
881
1117
If called like _is_dbus_thing("method") it returns a function
882
1118
suitable for use as predicate to inspect.getmembers().
884
return lambda obj: getattr(obj, "_dbus_is_{0}".format(thing),
1120
return lambda obj: getattr(obj, "_dbus_is_{}".format(thing),
887
1123
def _get_all_dbus_things(self, thing):
888
1124
"""Returns a generator of (name, attribute) pairs
890
return ((getattr(athing.__get__(self), "_dbus_name",
1126
return ((getattr(athing.__get__(self), "_dbus_name", name),
892
1127
athing.__get__(self))
893
1128
for cls in self.__class__.__mro__
894
1129
for name, athing in
895
inspect.getmembers(cls,
896
self._is_dbus_thing(thing)))
1130
inspect.getmembers(cls, self._is_dbus_thing(thing)))
1132
@dbus.service.method(dbus.INTROSPECTABLE_IFACE,
1133
out_signature = "s",
1134
path_keyword = 'object_path',
1135
connection_keyword = 'connection')
1136
def Introspect(self, object_path, connection):
1137
"""Overloading of standard D-Bus method.
1139
Inserts annotation tags on methods and signals.
1141
xmlstring = dbus.service.Object.Introspect(self, object_path,
1144
document = xml.dom.minidom.parseString(xmlstring)
1146
for if_tag in document.getElementsByTagName("interface"):
1147
# Add annotation tags
1148
for typ in ("method", "signal"):
1149
for tag in if_tag.getElementsByTagName(typ):
1151
for name, prop in (self.
1152
_get_all_dbus_things(typ)):
1153
if (name == tag.getAttribute("name")
1154
and prop._dbus_interface
1155
== if_tag.getAttribute("name")):
1156
annots.update(getattr(
1157
prop, "_dbus_annotations", {}))
1158
for name, value in annots.items():
1159
ann_tag = document.createElement(
1161
ann_tag.setAttribute("name", name)
1162
ann_tag.setAttribute("value", value)
1163
tag.appendChild(ann_tag)
1164
# Add interface annotation tags
1165
for annotation, value in dict(
1166
itertools.chain.from_iterable(
1167
annotations().items()
1168
for name, annotations
1169
in self._get_all_dbus_things("interface")
1170
if name == if_tag.getAttribute("name")
1172
ann_tag = document.createElement("annotation")
1173
ann_tag.setAttribute("name", annotation)
1174
ann_tag.setAttribute("value", value)
1175
if_tag.appendChild(ann_tag)
1176
# Fix argument name for the Introspect method itself
1177
if (if_tag.getAttribute("name")
1178
== dbus.INTROSPECTABLE_IFACE):
1179
for cn in if_tag.getElementsByTagName("method"):
1180
if cn.getAttribute("name") == "Introspect":
1181
for arg in cn.getElementsByTagName("arg"):
1182
if (arg.getAttribute("direction")
1184
arg.setAttribute("name",
1186
xmlstring = document.toxml("utf-8")
1188
except (AttributeError, xml.dom.DOMException,
1189
xml.parsers.expat.ExpatError) as error:
1190
logger.error("Failed to override Introspection method",
1195
class DBusObjectWithProperties(DBusObjectWithAnnotations):
1196
"""A D-Bus object with properties.
1198
Classes inheriting from this can use the dbus_service_property
1199
decorator to expose methods as D-Bus properties. It exposes the
1200
standard Get(), Set(), and GetAll() methods on the D-Bus.
898
1203
def _get_dbus_property(self, interface_name, property_name):
899
1204
"""Returns a bound method if one exists which is a D-Bus
900
1205
property with the specified name and interface.
902
for cls in self.__class__.__mro__:
903
for name, value in (inspect.getmembers
905
self._is_dbus_thing("property"))):
1207
for cls in self.__class__.__mro__:
1208
for name, value in inspect.getmembers(
1209
cls, self._is_dbus_thing("property")):
906
1210
if (value._dbus_name == property_name
907
1211
and value._dbus_interface == interface_name):
908
1212
return value.__get__(self)
910
1214
# No such property
911
raise DBusPropertyNotFound(self.dbus_object_path + ":"
912
+ interface_name + "."
915
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature="ss",
1215
raise DBusPropertyNotFound("{}:{}.{}".format(
1216
self.dbus_object_path, interface_name, property_name))
1219
def _get_all_interface_names(cls):
1220
"""Get a sequence of all interfaces supported by an object"""
1221
return (name for name in set(getattr(getattr(x, attr),
1222
"_dbus_interface", None)
1223
for x in (inspect.getmro(cls))
1225
if name is not None)
1227
@dbus.service.method(dbus.PROPERTIES_IFACE,
916
1229
out_signature="v")
917
1230
def Get(self, interface_name, property_name):
918
1231
"""Standard D-Bus property Get() method, see D-Bus standard.
995
1320
if prop._dbus_interface
996
1321
== if_tag.getAttribute("name")):
997
1322
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
1009
"_dbus_annotations",
1011
for name, value in annots.iteritems():
1012
ann_tag = document.createElement(
1014
ann_tag.setAttribute("name", name)
1015
ann_tag.setAttribute("value", value)
1016
tag.appendChild(ann_tag)
1017
# Add interface annotation tags
1018
for annotation, value in dict(
1019
itertools.chain.from_iterable(
1020
annotations().iteritems()
1021
for name, annotations in
1022
self._get_all_dbus_things("interface")
1023
if name == if_tag.getAttribute("name")
1025
ann_tag = document.createElement("annotation")
1026
ann_tag.setAttribute("name", annotation)
1027
ann_tag.setAttribute("value", value)
1028
if_tag.appendChild(ann_tag)
1323
# Add annotation tags for properties
1324
for tag in if_tag.getElementsByTagName("property"):
1326
for name, prop in self._get_all_dbus_things(
1328
if (name == tag.getAttribute("name")
1329
and prop._dbus_interface
1330
== if_tag.getAttribute("name")):
1331
annots.update(getattr(
1332
prop, "_dbus_annotations", {}))
1333
for name, value in annots.items():
1334
ann_tag = document.createElement(
1336
ann_tag.setAttribute("name", name)
1337
ann_tag.setAttribute("value", value)
1338
tag.appendChild(ann_tag)
1029
1339
# Add the names to the return values for the
1030
1340
# "org.freedesktop.DBus.Properties" methods
1031
1341
if (if_tag.getAttribute("name")
1049
1359
exc_info=error)
1050
1360
return xmlstring
1363
dbus.OBJECT_MANAGER_IFACE
1364
except AttributeError:
1365
dbus.OBJECT_MANAGER_IFACE = "org.freedesktop.DBus.ObjectManager"
1367
class DBusObjectWithObjectManager(DBusObjectWithAnnotations):
1368
"""A D-Bus object with an ObjectManager.
1370
Classes inheriting from this exposes the standard
1371
GetManagedObjects call and the InterfacesAdded and
1372
InterfacesRemoved signals on the standard
1373
"org.freedesktop.DBus.ObjectManager" interface.
1375
Note: No signals are sent automatically; they must be sent
1378
@dbus.service.method(dbus.OBJECT_MANAGER_IFACE,
1379
out_signature = "a{oa{sa{sv}}}")
1380
def GetManagedObjects(self):
1381
"""This function must be overridden"""
1382
raise NotImplementedError()
1384
@dbus.service.signal(dbus.OBJECT_MANAGER_IFACE,
1385
signature = "oa{sa{sv}}")
1386
def InterfacesAdded(self, object_path, interfaces_and_properties):
1389
@dbus.service.signal(dbus.OBJECT_MANAGER_IFACE, signature = "oas")
1390
def InterfacesRemoved(self, object_path, interfaces):
1393
@dbus.service.method(dbus.INTROSPECTABLE_IFACE,
1394
out_signature = "s",
1395
path_keyword = 'object_path',
1396
connection_keyword = 'connection')
1397
def Introspect(self, object_path, connection):
1398
"""Overloading of standard D-Bus method.
1400
Override return argument name of GetManagedObjects to be
1401
"objpath_interfaces_and_properties"
1403
xmlstring = DBusObjectWithAnnotations.Introspect(self,
1407
document = xml.dom.minidom.parseString(xmlstring)
1409
for if_tag in document.getElementsByTagName("interface"):
1410
# Fix argument name for the GetManagedObjects method
1411
if (if_tag.getAttribute("name")
1412
== dbus.OBJECT_MANAGER_IFACE):
1413
for cn in if_tag.getElementsByTagName("method"):
1414
if (cn.getAttribute("name")
1415
== "GetManagedObjects"):
1416
for arg in cn.getElementsByTagName("arg"):
1417
if (arg.getAttribute("direction")
1421
"objpath_interfaces"
1423
xmlstring = document.toxml("utf-8")
1425
except (AttributeError, xml.dom.DOMException,
1426
xml.parsers.expat.ExpatError) as error:
1427
logger.error("Failed to override Introspection method",
1053
1431
def datetime_to_dbus(dt, variant_level=0):
1054
1432
"""Convert a UTC datetime.datetime() to a D-Bus type."""
1056
1434
return dbus.String("", variant_level = variant_level)
1057
return dbus.String(dt.isoformat(),
1058
variant_level=variant_level)
1435
return dbus.String(dt.isoformat(), variant_level=variant_level)
1061
1438
def alternate_dbus_interfaces(alt_interface_names, deprecate=True):
1091
1469
# Ignore non-D-Bus attributes, and D-Bus attributes
1092
1470
# with the wrong interface name
1093
1471
if (not hasattr(attribute, "_dbus_interface")
1094
or not attribute._dbus_interface
1095
.startswith(orig_interface_name)):
1472
or not attribute._dbus_interface.startswith(
1473
orig_interface_name)):
1097
1475
# Create an alternate D-Bus interface name based on
1098
1476
# the current name
1099
alt_interface = (attribute._dbus_interface
1100
.replace(orig_interface_name,
1101
alt_interface_name))
1477
alt_interface = attribute._dbus_interface.replace(
1478
orig_interface_name, alt_interface_name)
1102
1479
interface_names.add(alt_interface)
1103
1480
# Is this a D-Bus signal?
1104
1481
if getattr(attribute, "_dbus_is_signal", False):
1105
# Extract the original non-method undecorated
1106
# function by black magic
1107
nonmethod_func = (dict(
1482
if sys.version_info.major == 2:
1483
# Extract the original non-method undecorated
1484
# function by black magic
1485
nonmethod_func = (dict(
1108
1486
zip(attribute.func_code.co_freevars,
1109
attribute.__closure__))["func"]
1487
attribute.__closure__))
1488
["func"].cell_contents)
1490
nonmethod_func = attribute
1111
1491
# Create a new, but exactly alike, function
1112
1492
# object, and decorate it to be a new D-Bus signal
1113
1493
# with the alternate D-Bus interface name
1114
new_function = (dbus.service.signal
1116
attribute._dbus_signature)
1117
(types.FunctionType(
1118
nonmethod_func.func_code,
1119
nonmethod_func.func_globals,
1120
nonmethod_func.func_name,
1121
nonmethod_func.func_defaults,
1122
nonmethod_func.func_closure)))
1494
if sys.version_info.major == 2:
1495
new_function = types.FunctionType(
1496
nonmethod_func.func_code,
1497
nonmethod_func.func_globals,
1498
nonmethod_func.func_name,
1499
nonmethod_func.func_defaults,
1500
nonmethod_func.func_closure)
1502
new_function = types.FunctionType(
1503
nonmethod_func.__code__,
1504
nonmethod_func.__globals__,
1505
nonmethod_func.__name__,
1506
nonmethod_func.__defaults__,
1507
nonmethod_func.__closure__)
1508
new_function = (dbus.service.signal(
1510
attribute._dbus_signature)(new_function))
1123
1511
# Copy annotations, if any
1125
new_function._dbus_annotations = (
1126
dict(attribute._dbus_annotations))
1513
new_function._dbus_annotations = dict(
1514
attribute._dbus_annotations)
1127
1515
except AttributeError:
1129
1517
# Define a creator of a function to call both the
1474
1885
self.approved_by_default = bool(value)
1476
1887
# ApprovalDelay - property
1477
@dbus_service_property(_interface, signature="t",
1888
@dbus_service_property(_interface,
1478
1890
access="readwrite")
1479
1891
def ApprovalDelay_dbus_property(self, value=None):
1480
1892
if value is None: # get
1481
return dbus.UInt64(self.approval_delay_milliseconds())
1893
return dbus.UInt64(self.approval_delay.total_seconds()
1482
1895
self.approval_delay = datetime.timedelta(0, 0, 0, value)
1484
1897
# ApprovalDuration - property
1485
@dbus_service_property(_interface, signature="t",
1898
@dbus_service_property(_interface,
1486
1900
access="readwrite")
1487
1901
def ApprovalDuration_dbus_property(self, value=None):
1488
1902
if value is None: # get
1489
return dbus.UInt64(timedelta_to_milliseconds(
1490
self.approval_duration))
1903
return dbus.UInt64(self.approval_duration.total_seconds()
1491
1905
self.approval_duration = datetime.timedelta(0, 0, 0, value)
1493
1907
# Name - property
1909
{"org.freedesktop.DBus.Property.EmitsChangedSignal": "const"})
1494
1910
@dbus_service_property(_interface, signature="s", access="read")
1495
1911
def Name_dbus_property(self):
1496
1912
return dbus.String(self.name)
1498
1914
# Fingerprint - property
1916
{"org.freedesktop.DBus.Property.EmitsChangedSignal": "const"})
1499
1917
@dbus_service_property(_interface, signature="s", access="read")
1500
1918
def Fingerprint_dbus_property(self):
1501
1919
return dbus.String(self.fingerprint)
1503
1921
# Host - property
1504
@dbus_service_property(_interface, signature="s",
1922
@dbus_service_property(_interface,
1505
1924
access="readwrite")
1506
1925
def Host_dbus_property(self, value=None):
1507
1926
if value is None: # get
1508
1927
return dbus.String(self.host)
1509
self.host = unicode(value)
1928
self.host = str(value)
1511
1930
# Created - property
1932
{"org.freedesktop.DBus.Property.EmitsChangedSignal": "const"})
1512
1933
@dbus_service_property(_interface, signature="s", access="read")
1513
1934
def Created_dbus_property(self):
1514
1935
return datetime_to_dbus(self.created)
1576
1999
gobject.source_remove(self.disable_initiator_tag)
1577
self.disable_initiator_tag = (
1578
gobject.timeout_add(
1579
timedelta_to_milliseconds(self.expires - now),
2000
self.disable_initiator_tag = gobject.timeout_add(
2001
int((self.expires - now).total_seconds() * 1000),
1582
2004
# ExtendedTimeout - property
1583
@dbus_service_property(_interface, signature="t",
2005
@dbus_service_property(_interface,
1584
2007
access="readwrite")
1585
2008
def ExtendedTimeout_dbus_property(self, value=None):
1586
2009
if value is None: # get
1587
return dbus.UInt64(self.extended_timeout_milliseconds())
2010
return dbus.UInt64(self.extended_timeout.total_seconds()
1588
2012
self.extended_timeout = datetime.timedelta(0, 0, 0, value)
1590
2014
# Interval - property
1591
@dbus_service_property(_interface, signature="t",
2015
@dbus_service_property(_interface,
1592
2017
access="readwrite")
1593
2018
def Interval_dbus_property(self, value=None):
1594
2019
if value is None: # get
1595
return dbus.UInt64(self.interval_milliseconds())
2020
return dbus.UInt64(self.interval.total_seconds() * 1000)
1596
2021
self.interval = datetime.timedelta(0, 0, 0, value)
1597
2022
if getattr(self, "checker_initiator_tag", None) is None:
1599
2024
if self.enabled:
1600
2025
# Reschedule checker run
1601
2026
gobject.source_remove(self.checker_initiator_tag)
1602
self.checker_initiator_tag = (gobject.timeout_add
1603
(value, self.start_checker))
1604
self.start_checker() # Start one now, too
2027
self.checker_initiator_tag = gobject.timeout_add(
2028
value, self.start_checker)
2029
self.start_checker() # Start one now, too
1606
2031
# Checker - property
1607
@dbus_service_property(_interface, signature="s",
2032
@dbus_service_property(_interface,
1608
2034
access="readwrite")
1609
2035
def Checker_dbus_property(self, value=None):
1610
2036
if value is None: # get
1611
2037
return dbus.String(self.checker_command)
1612
self.checker_command = unicode(value)
2038
self.checker_command = str(value)
1614
2040
# CheckerRunning - property
1615
@dbus_service_property(_interface, signature="b",
2041
@dbus_service_property(_interface,
1616
2043
access="readwrite")
1617
2044
def CheckerRunning_dbus_property(self, value=None):
1618
2045
if value is None: # get
1844
2266
def fingerprint(openpgp):
1845
2267
"Convert an OpenPGP bytestring to a hexdigit fingerprint"
1846
2268
# New GnuTLS "datum" with the OpenPGP public key
1847
datum = (gnutls.library.types
1848
.gnutls_datum_t(ctypes.cast(ctypes.c_char_p(openpgp),
1851
ctypes.c_uint(len(openpgp))))
2269
datum = gnutls.datum_t(
2270
ctypes.cast(ctypes.c_char_p(openpgp),
2271
ctypes.POINTER(ctypes.c_ubyte)),
2272
ctypes.c_uint(len(openpgp)))
1852
2273
# New empty GnuTLS certificate
1853
crt = gnutls.library.types.gnutls_openpgp_crt_t()
1854
(gnutls.library.functions
1855
.gnutls_openpgp_crt_init(ctypes.byref(crt)))
2274
crt = gnutls.openpgp_crt_t()
2275
gnutls.openpgp_crt_init(ctypes.byref(crt))
1856
2276
# Import the OpenPGP public key into the certificate
1857
(gnutls.library.functions
1858
.gnutls_openpgp_crt_import(crt, ctypes.byref(datum),
1859
gnutls.library.constants
1860
.GNUTLS_OPENPGP_FMT_RAW))
2277
gnutls.openpgp_crt_import(crt, ctypes.byref(datum),
2278
gnutls.OPENPGP_FMT_RAW)
1861
2279
# Verify the self signature in the key
1862
2280
crtverify = ctypes.c_uint()
1863
(gnutls.library.functions
1864
.gnutls_openpgp_crt_verify_self(crt, 0,
1865
ctypes.byref(crtverify)))
2281
gnutls.openpgp_crt_verify_self(crt, 0,
2282
ctypes.byref(crtverify))
1866
2283
if crtverify.value != 0:
1867
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
1868
raise (gnutls.errors.CertificateSecurityError
2284
gnutls.openpgp_crt_deinit(crt)
2285
raise gnutls.CertificateSecurityError("Verify failed")
1870
2286
# New buffer for the fingerprint
1871
2287
buf = ctypes.create_string_buffer(20)
1872
2288
buf_len = ctypes.c_size_t()
1873
2289
# Get the fingerprint from the certificate into the buffer
1874
(gnutls.library.functions
1875
.gnutls_openpgp_crt_get_fingerprint(crt, ctypes.byref(buf),
1876
ctypes.byref(buf_len)))
2290
gnutls.openpgp_crt_get_fingerprint(crt, ctypes.byref(buf),
2291
ctypes.byref(buf_len))
1877
2292
# Deinit the certificate
1878
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
2293
gnutls.openpgp_crt_deinit(crt)
1879
2294
# Convert the buffer to a Python bytestring
1880
2295
fpr = ctypes.string_at(buf, buf_len.value)
1881
2296
# Convert the bytestring to hexadecimal notation