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