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