383
416
follow_name_owner_changes=True),
384
417
avahi.DBUS_INTERFACE_SERVER)
385
418
self.server.connect_to_signal("StateChanged",
386
self.server_state_changed)
419
self.server_state_changed)
387
420
self.server_state_changed(self.server.GetState())
390
423
class AvahiServiceToSyslog(AvahiService):
424
def rename(self, *args, **kwargs):
392
425
"""Add the new name to the syslog messages"""
393
ret = AvahiService.rename(self)
394
syslogger.setFormatter(logging.Formatter
395
('Mandos ({0}) [%(process)d]:'
396
' %(levelname)s: %(message)s'
426
ret = AvahiService.rename(self, *args, **kwargs)
427
syslogger.setFormatter(logging.Formatter(
428
'Mandos ({}) [%(process)d]: %(levelname)s: %(message)s'
401
def timedelta_to_milliseconds(td):
402
"Convert a datetime.timedelta() to milliseconds"
403
return ((td.days * 24 * 60 * 60 * 1000)
404
+ (td.seconds * 1000)
405
+ (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))
408
680
class Client(object):
409
681
"""A representation of a client host served by this server.
621
878
# and every interval from then on.
622
879
if self.checker_initiator_tag is not None:
623
880
gobject.source_remove(self.checker_initiator_tag)
624
self.checker_initiator_tag = (gobject.timeout_add
625
(self.interval_milliseconds(),
881
self.checker_initiator_tag = gobject.timeout_add(
882
int(self.interval.total_seconds() * 1000),
627
884
# Schedule a disable() when 'timeout' has passed
628
885
if self.disable_initiator_tag is not None:
629
886
gobject.source_remove(self.disable_initiator_tag)
630
self.disable_initiator_tag = (gobject.timeout_add
631
(self.timeout_milliseconds(),
887
self.disable_initiator_tag = gobject.timeout_add(
888
int(self.timeout.total_seconds() * 1000), self.disable)
633
889
# Also start a new checker *right now*.
634
890
self.start_checker()
636
def checker_callback(self, pid, condition, command):
892
def checker_callback(self, source, condition, connection,
637
894
"""The checker has completed, so take appropriate actions."""
638
895
self.checker_callback_tag = None
639
896
self.checker = None
640
if os.WIFEXITED(condition):
641
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
642
904
if self.last_checker_status == 0:
643
905
logger.info("Checker for %(name)s succeeded",
645
907
self.checked_ok()
647
logger.info("Checker for %(name)s failed",
909
logger.info("Checker for %(name)s failed", vars(self))
650
911
self.last_checker_status = -1
912
self.last_checker_signal = -returncode
651
913
logger.warning("Checker for %(name)s crashed?",
654
917
def checked_ok(self):
655
918
"""Assert that the client has been seen, alive and well."""
656
919
self.last_checked_ok = datetime.datetime.utcnow()
657
920
self.last_checker_status = 0
921
self.last_checker_signal = None
658
922
self.bump_timeout()
660
924
def bump_timeout(self, timeout=None):
687
950
# than 'timeout' for the client to be disabled, which is as it
690
# If a checker exists, make sure it is not a zombie
692
pid, status = os.waitpid(self.checker.pid, os.WNOHANG)
693
except (AttributeError, OSError) as error:
694
if (isinstance(error, OSError)
695
and error.errno != errno.ECHILD):
699
logger.warning("Checker was a zombie")
700
gobject.source_remove(self.checker_callback_tag)
701
self.checker_callback(pid, status,
702
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")
703
957
# Start a new checker if needed
704
958
if self.checker is None:
705
959
# Escape attributes for the shell
706
escaped_attrs = dict(
707
(attr, re.escape(unicode(getattr(self, attr))))
709
self.runtime_expansions)
961
attr: re.escape(str(getattr(self, attr)))
962
for attr in self.runtime_expansions }
711
964
command = self.checker_command % escaped_attrs
712
965
except TypeError as error:
713
966
logger.error('Could not format string "%s"',
714
self.checker_command, exc_info=error)
715
return True # Try again later
967
self.checker_command,
969
return True # Try again later
716
970
self.current_checker_command = command
718
logger.info("Starting checker %r for %s",
720
# We don't need to redirect stdout and stderr, since
721
# in normal mode, that is already done by daemon(),
722
# and in debug mode we don't want to. (Stdin is
723
# always replaced by /dev/null.)
724
# The exception is when not debugging but nevertheless
725
# running in the foreground; use the previously
728
if (not self.server_settings["debug"]
729
and self.server_settings["foreground"]):
730
popen_args.update({"stdout": wnull,
732
self.checker = subprocess.Popen(command,
736
except OSError as error:
737
logger.error("Failed to start subprocess",
740
self.checker_callback_tag = (gobject.child_watch_add
742
self.checker_callback,
744
# The checker may have completed before the gobject
745
# watch was added. Check for this.
747
pid, status = os.waitpid(self.checker.pid, os.WNOHANG)
748
except OSError as error:
749
if error.errno == errno.ECHILD:
750
# This should never happen
751
logger.error("Child process vanished",
756
gobject.source_remove(self.checker_callback_tag)
757
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)
758
996
# Re-run this periodically if run by gobject.timeout_add
878
1117
If called like _is_dbus_thing("method") it returns a function
879
1118
suitable for use as predicate to inspect.getmembers().
881
return lambda obj: getattr(obj, "_dbus_is_{0}".format(thing),
1120
return lambda obj: getattr(obj, "_dbus_is_{}".format(thing),
884
1123
def _get_all_dbus_things(self, thing):
885
1124
"""Returns a generator of (name, attribute) pairs
887
return ((getattr(athing.__get__(self), "_dbus_name",
1126
return ((getattr(athing.__get__(self), "_dbus_name", name),
889
1127
athing.__get__(self))
890
1128
for cls in self.__class__.__mro__
891
1129
for name, athing in
892
inspect.getmembers(cls,
893
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.
895
1203
def _get_dbus_property(self, interface_name, property_name):
896
1204
"""Returns a bound method if one exists which is a D-Bus
897
1205
property with the specified name and interface.
899
for cls in self.__class__.__mro__:
900
for name, value in (inspect.getmembers
902
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")):
903
1210
if (value._dbus_name == property_name
904
1211
and value._dbus_interface == interface_name):
905
1212
return value.__get__(self)
907
1214
# No such property
908
raise DBusPropertyNotFound(self.dbus_object_path + ":"
909
+ interface_name + "."
912
@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,
913
1229
out_signature="v")
914
1230
def Get(self, interface_name, property_name):
915
1231
"""Standard D-Bus property Get() method, see D-Bus standard.
990
1320
if prop._dbus_interface
991
1321
== if_tag.getAttribute("name")):
992
1322
if_tag.appendChild(tag)
993
# Add annotation tags
994
for typ in ("method", "signal", "property"):
995
for tag in if_tag.getElementsByTagName(typ):
997
for name, prop in (self.
998
_get_all_dbus_things(typ)):
999
if (name == tag.getAttribute("name")
1000
and prop._dbus_interface
1001
== if_tag.getAttribute("name")):
1002
annots.update(getattr
1004
"_dbus_annotations",
1006
for name, value in annots.iteritems():
1007
ann_tag = document.createElement(
1009
ann_tag.setAttribute("name", name)
1010
ann_tag.setAttribute("value", value)
1011
tag.appendChild(ann_tag)
1012
# Add interface annotation tags
1013
for annotation, value in dict(
1014
itertools.chain.from_iterable(
1015
annotations().iteritems()
1016
for name, annotations in
1017
self._get_all_dbus_things("interface")
1018
if name == if_tag.getAttribute("name")
1020
ann_tag = document.createElement("annotation")
1021
ann_tag.setAttribute("name", annotation)
1022
ann_tag.setAttribute("value", value)
1023
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)
1024
1339
# Add the names to the return values for the
1025
1340
# "org.freedesktop.DBus.Properties" methods
1026
1341
if (if_tag.getAttribute("name")
1044
1359
exc_info=error)
1045
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",
1048
1431
def datetime_to_dbus(dt, variant_level=0):
1049
1432
"""Convert a UTC datetime.datetime() to a D-Bus type."""
1051
1434
return dbus.String("", variant_level = variant_level)
1052
return dbus.String(dt.isoformat(),
1053
variant_level=variant_level)
1435
return dbus.String(dt.isoformat(), variant_level=variant_level)
1056
1438
def alternate_dbus_interfaces(alt_interface_names, deprecate=True):
1086
1469
# Ignore non-D-Bus attributes, and D-Bus attributes
1087
1470
# with the wrong interface name
1088
1471
if (not hasattr(attribute, "_dbus_interface")
1089
or not attribute._dbus_interface
1090
.startswith(orig_interface_name)):
1472
or not attribute._dbus_interface.startswith(
1473
orig_interface_name)):
1092
1475
# Create an alternate D-Bus interface name based on
1093
1476
# the current name
1094
alt_interface = (attribute._dbus_interface
1095
.replace(orig_interface_name,
1096
alt_interface_name))
1477
alt_interface = attribute._dbus_interface.replace(
1478
orig_interface_name, alt_interface_name)
1097
1479
interface_names.add(alt_interface)
1098
1480
# Is this a D-Bus signal?
1099
1481
if getattr(attribute, "_dbus_is_signal", False):
1100
# Extract the original non-method undecorated
1101
# function by black magic
1102
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(
1103
1486
zip(attribute.func_code.co_freevars,
1104
attribute.__closure__))["func"]
1487
attribute.__closure__))
1488
["func"].cell_contents)
1490
nonmethod_func = attribute
1106
1491
# Create a new, but exactly alike, function
1107
1492
# object, and decorate it to be a new D-Bus signal
1108
1493
# with the alternate D-Bus interface name
1109
new_function = (dbus.service.signal
1111
attribute._dbus_signature)
1112
(types.FunctionType(
1113
nonmethod_func.func_code,
1114
nonmethod_func.func_globals,
1115
nonmethod_func.func_name,
1116
nonmethod_func.func_defaults,
1117
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))
1118
1511
# Copy annotations, if any
1120
new_function._dbus_annotations = (
1121
dict(attribute._dbus_annotations))
1513
new_function._dbus_annotations = dict(
1514
attribute._dbus_annotations)
1122
1515
except AttributeError:
1124
1517
# Define a creator of a function to call both the
1327
1741
DBusObjectWithProperties.__del__(self, *args, **kwargs)
1328
1742
Client.__del__(self, *args, **kwargs)
1330
def checker_callback(self, pid, condition, command,
1332
self.checker_callback_tag = None
1334
if os.WIFEXITED(condition):
1335
exitstatus = os.WEXITSTATUS(condition)
1744
def checker_callback(self, source, condition,
1745
connection, command, *args, **kwargs):
1746
ret = Client.checker_callback(self, source, condition,
1747
connection, command, *args,
1749
exitstatus = self.last_checker_status
1336
1751
# Emit D-Bus signal
1337
1752
self.CheckerCompleted(dbus.Int16(exitstatus),
1338
dbus.Int64(condition),
1753
# This is specific to GNU libC
1754
dbus.Int64(exitstatus << 8),
1339
1755
dbus.String(command))
1341
1757
# Emit D-Bus signal
1342
1758
self.CheckerCompleted(dbus.Int16(-1),
1343
dbus.Int64(condition),
1760
# This is specific to GNU libC
1762
| self.last_checker_signal),
1344
1763
dbus.String(command))
1346
return Client.checker_callback(self, pid, condition, command,
1349
1766
def start_checker(self, *args, **kwargs):
1350
old_checker = self.checker
1351
if self.checker is not None:
1352
old_checker_pid = self.checker.pid
1354
old_checker_pid = None
1767
old_checker_pid = getattr(self.checker, "pid", None)
1355
1768
r = Client.start_checker(self, *args, **kwargs)
1356
1769
# Only if new checker process was started
1357
1770
if (self.checker is not None
1473
1885
self.approved_by_default = bool(value)
1475
1887
# ApprovalDelay - property
1476
@dbus_service_property(_interface, signature="t",
1888
@dbus_service_property(_interface,
1477
1890
access="readwrite")
1478
1891
def ApprovalDelay_dbus_property(self, value=None):
1479
1892
if value is None: # get
1480
return dbus.UInt64(self.approval_delay_milliseconds())
1893
return dbus.UInt64(self.approval_delay.total_seconds()
1481
1895
self.approval_delay = datetime.timedelta(0, 0, 0, value)
1483
1897
# ApprovalDuration - property
1484
@dbus_service_property(_interface, signature="t",
1898
@dbus_service_property(_interface,
1485
1900
access="readwrite")
1486
1901
def ApprovalDuration_dbus_property(self, value=None):
1487
1902
if value is None: # get
1488
return dbus.UInt64(timedelta_to_milliseconds(
1489
self.approval_duration))
1903
return dbus.UInt64(self.approval_duration.total_seconds()
1490
1905
self.approval_duration = datetime.timedelta(0, 0, 0, value)
1492
1907
# Name - property
1909
{"org.freedesktop.DBus.Property.EmitsChangedSignal": "const"})
1493
1910
@dbus_service_property(_interface, signature="s", access="read")
1494
1911
def Name_dbus_property(self):
1495
1912
return dbus.String(self.name)
1497
1914
# Fingerprint - property
1916
{"org.freedesktop.DBus.Property.EmitsChangedSignal": "const"})
1498
1917
@dbus_service_property(_interface, signature="s", access="read")
1499
1918
def Fingerprint_dbus_property(self):
1500
1919
return dbus.String(self.fingerprint)
1502
1921
# Host - property
1503
@dbus_service_property(_interface, signature="s",
1922
@dbus_service_property(_interface,
1504
1924
access="readwrite")
1505
1925
def Host_dbus_property(self, value=None):
1506
1926
if value is None: # get
1507
1927
return dbus.String(self.host)
1508
self.host = unicode(value)
1928
self.host = str(value)
1510
1930
# Created - property
1932
{"org.freedesktop.DBus.Property.EmitsChangedSignal": "const"})
1511
1933
@dbus_service_property(_interface, signature="s", access="read")
1512
1934
def Created_dbus_property(self):
1513
1935
return datetime_to_dbus(self.created)
1575
1999
gobject.source_remove(self.disable_initiator_tag)
1576
self.disable_initiator_tag = (
1577
gobject.timeout_add(
1578
timedelta_to_milliseconds(self.expires - now),
2000
self.disable_initiator_tag = gobject.timeout_add(
2001
int((self.expires - now).total_seconds() * 1000),
1581
2004
# ExtendedTimeout - property
1582
@dbus_service_property(_interface, signature="t",
2005
@dbus_service_property(_interface,
1583
2007
access="readwrite")
1584
2008
def ExtendedTimeout_dbus_property(self, value=None):
1585
2009
if value is None: # get
1586
return dbus.UInt64(self.extended_timeout_milliseconds())
2010
return dbus.UInt64(self.extended_timeout.total_seconds()
1587
2012
self.extended_timeout = datetime.timedelta(0, 0, 0, value)
1589
2014
# Interval - property
1590
@dbus_service_property(_interface, signature="t",
2015
@dbus_service_property(_interface,
1591
2017
access="readwrite")
1592
2018
def Interval_dbus_property(self, value=None):
1593
2019
if value is None: # get
1594
return dbus.UInt64(self.interval_milliseconds())
2020
return dbus.UInt64(self.interval.total_seconds() * 1000)
1595
2021
self.interval = datetime.timedelta(0, 0, 0, value)
1596
2022
if getattr(self, "checker_initiator_tag", None) is None:
1598
2024
if self.enabled:
1599
2025
# Reschedule checker run
1600
2026
gobject.source_remove(self.checker_initiator_tag)
1601
self.checker_initiator_tag = (gobject.timeout_add
1602
(value, self.start_checker))
1603
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
1605
2031
# Checker - property
1606
@dbus_service_property(_interface, signature="s",
2032
@dbus_service_property(_interface,
1607
2034
access="readwrite")
1608
2035
def Checker_dbus_property(self, value=None):
1609
2036
if value is None: # get
1610
2037
return dbus.String(self.checker_command)
1611
self.checker_command = unicode(value)
2038
self.checker_command = str(value)
1613
2040
# CheckerRunning - property
1614
@dbus_service_property(_interface, signature="b",
2041
@dbus_service_property(_interface,
1615
2043
access="readwrite")
1616
2044
def CheckerRunning_dbus_property(self, value=None):
1617
2045
if value is None: # get
1843
2266
def fingerprint(openpgp):
1844
2267
"Convert an OpenPGP bytestring to a hexdigit fingerprint"
1845
2268
# New GnuTLS "datum" with the OpenPGP public key
1846
datum = (gnutls.library.types
1847
.gnutls_datum_t(ctypes.cast(ctypes.c_char_p(openpgp),
1850
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)))
1851
2273
# New empty GnuTLS certificate
1852
crt = gnutls.library.types.gnutls_openpgp_crt_t()
1853
(gnutls.library.functions
1854
.gnutls_openpgp_crt_init(ctypes.byref(crt)))
2274
crt = gnutls.openpgp_crt_t()
2275
gnutls.openpgp_crt_init(ctypes.byref(crt))
1855
2276
# Import the OpenPGP public key into the certificate
1856
(gnutls.library.functions
1857
.gnutls_openpgp_crt_import(crt, ctypes.byref(datum),
1858
gnutls.library.constants
1859
.GNUTLS_OPENPGP_FMT_RAW))
2277
gnutls.openpgp_crt_import(crt, ctypes.byref(datum),
2278
gnutls.OPENPGP_FMT_RAW)
1860
2279
# Verify the self signature in the key
1861
2280
crtverify = ctypes.c_uint()
1862
(gnutls.library.functions
1863
.gnutls_openpgp_crt_verify_self(crt, 0,
1864
ctypes.byref(crtverify)))
2281
gnutls.openpgp_crt_verify_self(crt, 0,
2282
ctypes.byref(crtverify))
1865
2283
if crtverify.value != 0:
1866
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
1867
raise (gnutls.errors.CertificateSecurityError
2284
gnutls.openpgp_crt_deinit(crt)
2285
raise gnutls.CertificateSecurityError("Verify failed")
1869
2286
# New buffer for the fingerprint
1870
2287
buf = ctypes.create_string_buffer(20)
1871
2288
buf_len = ctypes.c_size_t()
1872
2289
# Get the fingerprint from the certificate into the buffer
1873
(gnutls.library.functions
1874
.gnutls_openpgp_crt_get_fingerprint(crt, ctypes.byref(buf),
1875
ctypes.byref(buf_len)))
2290
gnutls.openpgp_crt_get_fingerprint(crt, ctypes.byref(buf),
2291
ctypes.byref(buf_len))
1876
2292
# Deinit the certificate
1877
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
2293
gnutls.openpgp_crt_deinit(crt)
1878
2294
# Convert the buffer to a Python bytestring
1879
2295
fpr = ctypes.string_at(buf, buf_len.value)
1880
2296
# Convert the bytestring to hexadecimal notation