468
443
if error.errno != errno.ESRCH: # No such process
470
445
self.checker = None
447
self.PropertyChanged(dbus.String(u"checker_running"),
448
dbus.Boolean(False, variant_level=1))
472
450
def still_valid(self):
473
451
"""Has the timeout not yet passed for this client?"""
474
if not getattr(self, u"enabled", False):
452
if not getattr(self, "enabled", False):
476
454
now = datetime.datetime.utcnow()
477
455
if self.last_checked_ok is None:
478
456
return now < (self.created + self.timeout)
480
458
return now < (self.last_checked_ok + self.timeout)
483
def dbus_service_property(dbus_interface, signature=u"v",
484
access=u"readwrite", byte_arrays=False):
485
"""Decorators for marking methods of a DBusObjectWithProperties to
486
become properties on the D-Bus.
488
The decorated method will be called with no arguments by "Get"
489
and with one argument by "Set".
491
The parameters, where they are supported, are the same as
492
dbus.service.method, except there is only "signature", since the
493
type from Get() and the type sent to Set() is the same.
496
func._dbus_is_property = True
497
func._dbus_interface = dbus_interface
498
func._dbus_signature = signature
499
func._dbus_access = access
500
func._dbus_name = func.__name__
501
if func._dbus_name.endswith(u"_dbus_property"):
502
func._dbus_name = func._dbus_name[:-14]
503
func._dbus_get_args_options = {u'byte_arrays': byte_arrays }
508
class DBusPropertyException(dbus.exceptions.DBusException):
509
"""A base class for D-Bus property-related exceptions
511
def __unicode__(self):
512
return unicode(str(self))
515
class DBusPropertyAccessException(DBusPropertyException):
516
"""A property's access permissions disallows an operation.
521
class DBusPropertyNotFound(DBusPropertyException):
522
"""An attempt was made to access a non-existing property.
527
class DBusObjectWithProperties(dbus.service.Object):
528
"""A D-Bus object with properties.
530
Classes inheriting from this can use the dbus_service_property
531
decorator to expose methods as D-Bus properties. It exposes the
532
standard Get(), Set(), and GetAll() methods on the D-Bus.
536
def _is_dbus_property(obj):
537
return getattr(obj, u"_dbus_is_property", False)
539
def _get_all_dbus_properties(self):
540
"""Returns a generator of (name, attribute) pairs
542
return ((prop._dbus_name, prop)
544
inspect.getmembers(self, self._is_dbus_property))
546
def _get_dbus_property(self, interface_name, property_name):
547
"""Returns a bound method if one exists which is a D-Bus
548
property with the specified name and interface.
550
for name in (property_name,
551
property_name + u"_dbus_property"):
552
prop = getattr(self, name, None)
554
or not self._is_dbus_property(prop)
555
or prop._dbus_name != property_name
556
or (interface_name and prop._dbus_interface
557
and interface_name != prop._dbus_interface)):
561
raise DBusPropertyNotFound(self.dbus_object_path + u":"
562
+ interface_name + u"."
565
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature=u"ss",
567
def Get(self, interface_name, property_name):
568
"""Standard D-Bus property Get() method, see D-Bus standard.
570
prop = self._get_dbus_property(interface_name, property_name)
571
if prop._dbus_access == u"write":
572
raise DBusPropertyAccessException(property_name)
574
if not hasattr(value, u"variant_level"):
576
return type(value)(value, variant_level=value.variant_level+1)
578
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature=u"ssv")
579
def Set(self, interface_name, property_name, value):
580
"""Standard D-Bus property Set() method, see D-Bus standard.
582
prop = self._get_dbus_property(interface_name, property_name)
583
if prop._dbus_access == u"read":
584
raise DBusPropertyAccessException(property_name)
585
if prop._dbus_get_args_options[u"byte_arrays"]:
586
value = dbus.ByteArray(''.join(unichr(byte)
590
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature=u"s",
591
out_signature=u"a{sv}")
592
def GetAll(self, interface_name):
593
"""Standard D-Bus property GetAll() method, see D-Bus
596
Note: Will not include properties with access="write".
599
for name, prop in self._get_all_dbus_properties():
601
and interface_name != prop._dbus_interface):
602
# Interface non-empty but did not match
604
# Ignore write-only properties
605
if prop._dbus_access == u"write":
608
if not hasattr(value, u"variant_level"):
611
all[name] = type(value)(value, variant_level=
612
value.variant_level+1)
613
return dbus.Dictionary(all, signature=u"sv")
615
@dbus.service.method(dbus.INTROSPECTABLE_IFACE,
617
path_keyword='object_path',
618
connection_keyword='connection')
619
def Introspect(self, object_path, connection):
620
"""Standard D-Bus method, overloaded to insert property tags.
622
xmlstring = dbus.service.Object.Introspect(self, object_path,
624
document = xml.dom.minidom.parseString(xmlstring)
626
def make_tag(document, name, prop):
627
e = document.createElement(u"property")
628
e.setAttribute(u"name", name)
629
e.setAttribute(u"type", prop._dbus_signature)
630
e.setAttribute(u"access", prop._dbus_access)
632
for if_tag in document.getElementsByTagName(u"interface"):
633
for tag in (make_tag(document, name, prop)
635
in self._get_all_dbus_properties()
636
if prop._dbus_interface
637
== if_tag.getAttribute(u"name")):
638
if_tag.appendChild(tag)
639
xmlstring = document.toxml(u"utf-8")
644
class ClientDBus(Client, DBusObjectWithProperties):
645
"""A Client class using D-Bus
648
dbus_object_path: dbus.ObjectPath
649
bus: dbus.SystemBus()
651
# dbus.service.Object doesn't use super(), so we can't either.
653
def __init__(self, bus = None, *args, **kwargs):
655
Client.__init__(self, *args, **kwargs)
656
# Only now, when this client is initialized, can it show up on
658
self.dbus_object_path = (dbus.ObjectPath
660
+ self.name.replace(u".", u"_")))
661
DBusObjectWithProperties.__init__(self, self.bus,
662
self.dbus_object_path)
665
def _datetime_to_dbus(dt, variant_level=0):
666
"""Convert a UTC datetime.datetime() to a D-Bus type."""
667
return dbus.String(dt.isoformat(),
668
variant_level=variant_level)
671
oldstate = getattr(self, u"enabled", False)
672
r = Client.enable(self)
673
if oldstate != self.enabled:
675
self.PropertyChanged(dbus.String(u"enabled"),
676
dbus.Boolean(True, variant_level=1))
677
self.PropertyChanged(
678
dbus.String(u"last_enabled"),
679
self._datetime_to_dbus(self.last_enabled,
683
def disable(self, signal = True):
684
oldstate = getattr(self, u"enabled", False)
685
r = Client.disable(self)
686
if signal and oldstate != self.enabled:
688
self.PropertyChanged(dbus.String(u"enabled"),
689
dbus.Boolean(False, variant_level=1))
692
def __del__(self, *args, **kwargs):
694
self.remove_from_connection()
697
if hasattr(DBusObjectWithProperties, u"__del__"):
698
DBusObjectWithProperties.__del__(self, *args, **kwargs)
699
Client.__del__(self, *args, **kwargs)
701
def checker_callback(self, pid, condition, command,
703
self.checker_callback_tag = None
706
self.PropertyChanged(dbus.String(u"checker_running"),
707
dbus.Boolean(False, variant_level=1))
708
if os.WIFEXITED(condition):
709
exitstatus = os.WEXITSTATUS(condition)
711
self.CheckerCompleted(dbus.Int16(exitstatus),
712
dbus.Int64(condition),
713
dbus.String(command))
716
self.CheckerCompleted(dbus.Int16(-1),
717
dbus.Int64(condition),
718
dbus.String(command))
720
return Client.checker_callback(self, pid, condition, command,
723
def checked_ok(self, *args, **kwargs):
724
r = Client.checked_ok(self, *args, **kwargs)
726
self.PropertyChanged(
727
dbus.String(u"last_checked_ok"),
728
(self._datetime_to_dbus(self.last_checked_ok,
732
def start_checker(self, *args, **kwargs):
733
old_checker = self.checker
734
if self.checker is not None:
735
old_checker_pid = self.checker.pid
737
old_checker_pid = None
738
r = Client.start_checker(self, *args, **kwargs)
739
# Only if new checker process was started
740
if (self.checker is not None
741
and old_checker_pid != self.checker.pid):
743
self.CheckerStarted(self.current_checker_command)
744
self.PropertyChanged(
745
dbus.String(u"checker_running"),
746
dbus.Boolean(True, variant_level=1))
749
def stop_checker(self, *args, **kwargs):
750
old_checker = getattr(self, u"checker", None)
751
r = Client.stop_checker(self, *args, **kwargs)
752
if (old_checker is not None
753
and getattr(self, u"checker", None) is None):
754
self.PropertyChanged(dbus.String(u"checker_running"),
755
dbus.Boolean(False, variant_level=1))
758
460
## D-Bus methods & signals
759
461
_interface = u"se.bsnet.fukt.Mandos.Client"
464
CheckedOK = dbus.service.method(_interface)(checked_ok)
465
CheckedOK.__name__ = "CheckedOK"
761
467
# CheckerCompleted - signal
762
@dbus.service.signal(_interface, signature=u"nxs")
468
@dbus.service.signal(_interface, signature="nxs")
763
469
def CheckerCompleted(self, exitcode, waitstatus, command):
767
473
# CheckerStarted - signal
768
@dbus.service.signal(_interface, signature=u"s")
474
@dbus.service.signal(_interface, signature="s")
769
475
def CheckerStarted(self, command):
479
# GetAllProperties - method
480
@dbus.service.method(_interface, out_signature="a{sv}")
481
def GetAllProperties(self):
483
return dbus.Dictionary({
485
dbus.String(self.name, variant_level=1),
486
dbus.String("fingerprint"):
487
dbus.String(self.fingerprint, variant_level=1),
489
dbus.String(self.host, variant_level=1),
490
dbus.String("created"):
491
_datetime_to_dbus(self.created, variant_level=1),
492
dbus.String("last_enabled"):
493
(_datetime_to_dbus(self.last_enabled,
495
if self.last_enabled is not None
496
else dbus.Boolean(False, variant_level=1)),
497
dbus.String("enabled"):
498
dbus.Boolean(self.enabled, variant_level=1),
499
dbus.String("last_checked_ok"):
500
(_datetime_to_dbus(self.last_checked_ok,
502
if self.last_checked_ok is not None
503
else dbus.Boolean (False, variant_level=1)),
504
dbus.String("timeout"):
505
dbus.UInt64(self.timeout_milliseconds(),
507
dbus.String("interval"):
508
dbus.UInt64(self.interval_milliseconds(),
510
dbus.String("checker"):
511
dbus.String(self.checker_command,
513
dbus.String("checker_running"):
514
dbus.Boolean(self.checker is not None,
516
dbus.String("object_path"):
517
dbus.ObjectPath(self.dbus_object_path,
521
# IsStillValid - method
522
IsStillValid = (dbus.service.method(_interface, out_signature="b")
524
IsStillValid.__name__ = "IsStillValid"
773
526
# PropertyChanged - signal
774
@dbus.service.signal(_interface, signature=u"sv")
527
@dbus.service.signal(_interface, signature="sv")
775
528
def PropertyChanged(self, property, value):
779
# ReceivedSecret - signal
780
@dbus.service.signal(_interface)
781
def ReceivedSecret(self):
786
@dbus.service.signal(_interface)
792
@dbus_service_property(_interface, signature=u"s", access=u"read")
793
def name_dbus_property(self):
794
return dbus.String(self.name)
796
# fingerprint - property
797
@dbus_service_property(_interface, signature=u"s", access=u"read")
798
def fingerprint_dbus_property(self):
799
return dbus.String(self.fingerprint)
802
@dbus_service_property(_interface, signature=u"s",
804
def host_dbus_property(self, value=None):
805
if value is None: # get
806
return dbus.String(self.host)
809
self.PropertyChanged(dbus.String(u"host"),
810
dbus.String(value, variant_level=1))
813
@dbus_service_property(_interface, signature=u"s", access=u"read")
814
def created_dbus_property(self):
815
return dbus.String(self._datetime_to_dbus(self.created))
817
# last_enabled - property
818
@dbus_service_property(_interface, signature=u"s", access=u"read")
819
def last_enabled_dbus_property(self):
820
if self.last_enabled is None:
821
return dbus.String(u"")
822
return dbus.String(self._datetime_to_dbus(self.last_enabled))
825
@dbus_service_property(_interface, signature=u"b",
827
def enabled_dbus_property(self, value=None):
828
if value is None: # get
829
return dbus.Boolean(self.enabled)
835
# last_checked_ok - property
836
@dbus_service_property(_interface, signature=u"s", access=u"read")
837
def last_checked_ok_dbus_property(self):
838
if self.last_checked_ok is None:
839
return dbus.String(u"")
840
return dbus.String(self._datetime_to_dbus(self
844
@dbus_service_property(_interface, signature=u"t",
846
def timeout_dbus_property(self, value=None):
847
if value is None: # get
848
return dbus.UInt64(self.timeout_milliseconds())
849
self.timeout = datetime.timedelta(0, 0, 0, value)
851
self.PropertyChanged(dbus.String(u"timeout"),
852
dbus.UInt64(value, variant_level=1))
853
if getattr(self, u"disable_initiator_tag", None) is None:
856
gobject.source_remove(self.disable_initiator_tag)
857
self.disable_initiator_tag = None
859
_timedelta_to_milliseconds((self
865
# The timeout has passed
868
self.disable_initiator_tag = (gobject.timeout_add
869
(time_to_die, self.disable))
871
# interval - property
872
@dbus_service_property(_interface, signature=u"t",
874
def interval_dbus_property(self, value=None):
875
if value is None: # get
876
return dbus.UInt64(self.interval_milliseconds())
877
self.interval = datetime.timedelta(0, 0, 0, value)
879
self.PropertyChanged(dbus.String(u"interval"),
880
dbus.UInt64(value, variant_level=1))
881
if getattr(self, u"checker_initiator_tag", None) is None:
883
# Reschedule checker run
884
gobject.source_remove(self.checker_initiator_tag)
885
self.checker_initiator_tag = (gobject.timeout_add
886
(value, self.start_checker))
887
self.start_checker() # Start one now, too
890
@dbus_service_property(_interface, signature=u"s",
892
def checker_dbus_property(self, value=None):
893
if value is None: # get
894
return dbus.String(self.checker_command)
895
self.checker_command = value
532
# SetChecker - method
533
@dbus.service.method(_interface, in_signature="s")
534
def SetChecker(self, checker):
535
"D-Bus setter method"
536
self.checker_command = checker
896
537
# Emit D-Bus signal
897
538
self.PropertyChanged(dbus.String(u"checker"),
898
539
dbus.String(self.checker_command,
899
540
variant_level=1))
901
# checker_running - property
902
@dbus_service_property(_interface, signature=u"b",
904
def checker_running_dbus_property(self, value=None):
905
if value is None: # get
906
return dbus.Boolean(self.checker is not None)
912
# object_path - property
913
@dbus_service_property(_interface, signature=u"o", access=u"read")
914
def object_path_dbus_property(self):
915
return self.dbus_object_path # is already a dbus.ObjectPath
917
# secret = property xxx
918
@dbus_service_property(_interface, signature=u"ay",
919
access=u"write", byte_arrays=True)
920
def secret_dbus_property(self, value):
921
self.secret = str(value)
543
@dbus.service.method(_interface, in_signature="s")
544
def SetHost(self, host):
545
"D-Bus setter method"
548
self.PropertyChanged(dbus.String(u"host"),
549
dbus.String(self.host, variant_level=1))
551
# SetInterval - method
552
@dbus.service.method(_interface, in_signature="t")
553
def SetInterval(self, milliseconds):
554
self.interval = datetime.timedelta(0, 0, 0, milliseconds)
556
self.PropertyChanged(dbus.String(u"interval"),
557
(dbus.UInt64(self.interval_milliseconds(),
561
@dbus.service.method(_interface, in_signature="ay",
563
def SetSecret(self, secret):
564
"D-Bus setter method"
565
self.secret = str(secret)
567
# SetTimeout - method
568
@dbus.service.method(_interface, in_signature="t")
569
def SetTimeout(self, milliseconds):
570
self.timeout = datetime.timedelta(0, 0, 0, milliseconds)
572
self.PropertyChanged(dbus.String(u"timeout"),
573
(dbus.UInt64(self.timeout_milliseconds(),
577
Enable = dbus.service.method(_interface)(enable)
578
Enable.__name__ = "Enable"
580
# StartChecker - method
581
@dbus.service.method(_interface)
582
def StartChecker(self):
587
@dbus.service.method(_interface)
592
# StopChecker - method
593
StopChecker = dbus.service.method(_interface)(stop_checker)
594
StopChecker.__name__ = "StopChecker"
926
class ClientHandler(socketserver.BaseRequestHandler, object):
927
"""A class to handle client connections.
929
Instantiated once for each connection to handle it.
599
def peer_certificate(session):
600
"Return the peer's OpenPGP certificate as a bytestring"
601
# If not an OpenPGP certificate...
602
if (gnutls.library.functions
603
.gnutls_certificate_type_get(session._c_object)
604
!= gnutls.library.constants.GNUTLS_CRT_OPENPGP):
605
# ...do the normal thing
606
return session.peer_certificate
607
list_size = ctypes.c_uint(1)
608
cert_list = (gnutls.library.functions
609
.gnutls_certificate_get_peers
610
(session._c_object, ctypes.byref(list_size)))
611
if not bool(cert_list) and list_size.value != 0:
612
raise gnutls.errors.GNUTLSError("error getting peer"
614
if list_size.value == 0:
617
return ctypes.string_at(cert.data, cert.size)
620
def fingerprint(openpgp):
621
"Convert an OpenPGP bytestring to a hexdigit fingerprint string"
622
# New GnuTLS "datum" with the OpenPGP public key
623
datum = (gnutls.library.types
624
.gnutls_datum_t(ctypes.cast(ctypes.c_char_p(openpgp),
627
ctypes.c_uint(len(openpgp))))
628
# New empty GnuTLS certificate
629
crt = gnutls.library.types.gnutls_openpgp_crt_t()
630
(gnutls.library.functions
631
.gnutls_openpgp_crt_init(ctypes.byref(crt)))
632
# Import the OpenPGP public key into the certificate
633
(gnutls.library.functions
634
.gnutls_openpgp_crt_import(crt, ctypes.byref(datum),
635
gnutls.library.constants
636
.GNUTLS_OPENPGP_FMT_RAW))
637
# Verify the self signature in the key
638
crtverify = ctypes.c_uint()
639
(gnutls.library.functions
640
.gnutls_openpgp_crt_verify_self(crt, 0, ctypes.byref(crtverify)))
641
if crtverify.value != 0:
642
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
643
raise gnutls.errors.CertificateSecurityError("Verify failed")
644
# New buffer for the fingerprint
645
buf = ctypes.create_string_buffer(20)
646
buf_len = ctypes.c_size_t()
647
# Get the fingerprint from the certificate into the buffer
648
(gnutls.library.functions
649
.gnutls_openpgp_crt_get_fingerprint(crt, ctypes.byref(buf),
650
ctypes.byref(buf_len)))
651
# Deinit the certificate
652
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
653
# Convert the buffer to a Python bytestring
654
fpr = ctypes.string_at(buf, buf_len.value)
655
# Convert the bytestring to hexadecimal notation
656
hex_fpr = u''.join(u"%02X" % ord(char) for char in fpr)
660
class TCP_handler(SocketServer.BaseRequestHandler, object):
661
"""A TCP request handler class.
662
Instantiated by IPv6_TCPServer for each request to handle it.
930
663
Note: This will run in its own forked process."""
932
665
def handle(self):
933
666
logger.info(u"TCP connection from: %s",
934
667
unicode(self.client_address))
935
logger.debug(u"IPC Pipe FD: %d", self.server.pipe[1])
936
# Open IPC pipe to parent process
937
with closing(os.fdopen(self.server.pipe[1], u"w", 1)) as ipc:
938
session = (gnutls.connection
939
.ClientSession(self.request,
943
line = self.request.makefile().readline()
944
logger.debug(u"Protocol version: %r", line)
946
if int(line.strip().split()[0]) > 1:
948
except (ValueError, IndexError, RuntimeError), error:
949
logger.error(u"Unknown protocol version: %s", error)
952
# Note: gnutls.connection.X509Credentials is really a
953
# generic GnuTLS certificate credentials object so long as
954
# no X.509 keys are added to it. Therefore, we can use it
955
# here despite using OpenPGP certificates.
957
#priority = u':'.join((u"NONE", u"+VERS-TLS1.1",
958
# u"+AES-256-CBC", u"+SHA1",
959
# u"+COMP-NULL", u"+CTYPE-OPENPGP",
961
# Use a fallback default, since this MUST be set.
962
priority = self.server.gnutls_priority
965
(gnutls.library.functions
966
.gnutls_priority_set_direct(session._c_object,
971
except gnutls.errors.GNUTLSError, error:
972
logger.warning(u"Handshake failed: %s", error)
973
# Do not run session.bye() here: the session is not
974
# established. Just abandon the request.
976
logger.debug(u"Handshake succeeded")
978
fpr = self.fingerprint(self.peer_certificate(session))
979
except (TypeError, gnutls.errors.GNUTLSError), error:
980
logger.warning(u"Bad certificate: %s", error)
983
logger.debug(u"Fingerprint: %s", fpr)
985
for c in self.server.clients:
986
if c.fingerprint == fpr:
990
ipc.write(u"NOTFOUND %s %s\n"
991
% (fpr, unicode(self.client_address)))
994
# Have to check if client.still_valid(), since it is
995
# possible that the client timed out while establishing
996
# the GnuTLS session.
997
if not client.still_valid():
998
ipc.write(u"INVALID %s\n" % client.name)
1001
ipc.write(u"SENDING %s\n" % client.name)
1003
while sent_size < len(client.secret):
1004
sent = session.send(client.secret[sent_size:])
1005
logger.debug(u"Sent: %d, remaining: %d",
1006
sent, len(client.secret)
1007
- (sent_size + sent))
1012
def peer_certificate(session):
1013
"Return the peer's OpenPGP certificate as a bytestring"
1014
# If not an OpenPGP certificate...
1015
if (gnutls.library.functions
1016
.gnutls_certificate_type_get(session._c_object)
1017
!= gnutls.library.constants.GNUTLS_CRT_OPENPGP):
1018
# ...do the normal thing
1019
return session.peer_certificate
1020
list_size = ctypes.c_uint(1)
1021
cert_list = (gnutls.library.functions
1022
.gnutls_certificate_get_peers
1023
(session._c_object, ctypes.byref(list_size)))
1024
if not bool(cert_list) and list_size.value != 0:
1025
raise gnutls.errors.GNUTLSError(u"error getting peer"
1027
if list_size.value == 0:
1030
return ctypes.string_at(cert.data, cert.size)
1033
def fingerprint(openpgp):
1034
"Convert an OpenPGP bytestring to a hexdigit fingerprint"
1035
# New GnuTLS "datum" with the OpenPGP public key
1036
datum = (gnutls.library.types
1037
.gnutls_datum_t(ctypes.cast(ctypes.c_char_p(openpgp),
1040
ctypes.c_uint(len(openpgp))))
1041
# New empty GnuTLS certificate
1042
crt = gnutls.library.types.gnutls_openpgp_crt_t()
1043
(gnutls.library.functions
1044
.gnutls_openpgp_crt_init(ctypes.byref(crt)))
1045
# Import the OpenPGP public key into the certificate
1046
(gnutls.library.functions
1047
.gnutls_openpgp_crt_import(crt, ctypes.byref(datum),
1048
gnutls.library.constants
1049
.GNUTLS_OPENPGP_FMT_RAW))
1050
# Verify the self signature in the key
1051
crtverify = ctypes.c_uint()
1052
(gnutls.library.functions
1053
.gnutls_openpgp_crt_verify_self(crt, 0,
1054
ctypes.byref(crtverify)))
1055
if crtverify.value != 0:
1056
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
1057
raise (gnutls.errors.CertificateSecurityError
1059
# New buffer for the fingerprint
1060
buf = ctypes.create_string_buffer(20)
1061
buf_len = ctypes.c_size_t()
1062
# Get the fingerprint from the certificate into the buffer
1063
(gnutls.library.functions
1064
.gnutls_openpgp_crt_get_fingerprint(crt, ctypes.byref(buf),
1065
ctypes.byref(buf_len)))
1066
# Deinit the certificate
1067
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
1068
# Convert the buffer to a Python bytestring
1069
fpr = ctypes.string_at(buf, buf_len.value)
1070
# Convert the bytestring to hexadecimal notation
1071
hex_fpr = u''.join(u"%02X" % ord(char) for char in fpr)
1075
class ForkingMixInWithPipe(socketserver.ForkingMixIn, object):
1076
"""Like socketserver.ForkingMixIn, but also pass a pipe."""
1077
def process_request(self, request, client_address):
1078
"""Overrides and wraps the original process_request().
1080
This function creates a new pipe in self.pipe
1082
self.pipe = os.pipe()
1083
super(ForkingMixInWithPipe,
1084
self).process_request(request, client_address)
1085
os.close(self.pipe[1]) # close write end
1086
self.add_pipe(self.pipe[0])
1087
def add_pipe(self, pipe):
1088
"""Dummy function; override as necessary"""
1092
class IPv6_TCPServer(ForkingMixInWithPipe,
1093
socketserver.TCPServer, object):
1094
"""IPv6-capable TCP server. Accepts 'None' as address and/or port
668
session = (gnutls.connection
669
.ClientSession(self.request,
673
line = self.request.makefile().readline()
674
logger.debug(u"Protocol version: %r", line)
676
if int(line.strip().split()[0]) > 1:
678
except (ValueError, IndexError, RuntimeError), error:
679
logger.error(u"Unknown protocol version: %s", error)
682
# Note: gnutls.connection.X509Credentials is really a generic
683
# GnuTLS certificate credentials object so long as no X.509
684
# keys are added to it. Therefore, we can use it here despite
685
# using OpenPGP certificates.
687
#priority = ':'.join(("NONE", "+VERS-TLS1.1", "+AES-256-CBC",
688
# "+SHA1", "+COMP-NULL", "+CTYPE-OPENPGP",
690
# Use a fallback default, since this MUST be set.
691
priority = self.server.settings.get("priority", "NORMAL")
692
(gnutls.library.functions
693
.gnutls_priority_set_direct(session._c_object,
698
except gnutls.errors.GNUTLSError, error:
699
logger.warning(u"Handshake failed: %s", error)
700
# Do not run session.bye() here: the session is not
701
# established. Just abandon the request.
703
logger.debug(u"Handshake succeeded")
705
fpr = fingerprint(peer_certificate(session))
706
except (TypeError, gnutls.errors.GNUTLSError), error:
707
logger.warning(u"Bad certificate: %s", error)
710
logger.debug(u"Fingerprint: %s", fpr)
712
for c in self.server.clients:
713
if c.fingerprint == fpr:
717
logger.warning(u"Client not found for fingerprint: %s",
721
# Have to check if client.still_valid(), since it is possible
722
# that the client timed out while establishing the GnuTLS
724
if not client.still_valid():
725
logger.warning(u"Client %(name)s is invalid",
729
## This won't work here, since we're in a fork.
730
# client.checked_ok()
732
while sent_size < len(client.secret):
733
sent = session.send(client.secret[sent_size:])
734
logger.debug(u"Sent: %d, remaining: %d",
735
sent, len(client.secret)
736
- (sent_size + sent))
741
class IPv6_TCPServer(SocketServer.ForkingMixIn,
742
SocketServer.TCPServer, object):
743
"""IPv6-capable TCP server. Accepts 'None' as address and/or port.
745
settings: Server settings
746
clients: Set() of Client objects
1097
747
enabled: Boolean; whether this server is activated yet
1098
interface: None or a network interface name (string)
1099
use_ipv6: Boolean; to use IPv6 or not
1101
def __init__(self, server_address, RequestHandlerClass,
1102
interface=None, use_ipv6=True):
1103
self.interface = interface
1105
self.address_family = socket.AF_INET6
1106
socketserver.TCPServer.__init__(self, server_address,
1107
RequestHandlerClass)
749
address_family = socket.AF_INET6
750
def __init__(self, *args, **kwargs):
751
if "settings" in kwargs:
752
self.settings = kwargs["settings"]
753
del kwargs["settings"]
754
if "clients" in kwargs:
755
self.clients = kwargs["clients"]
756
del kwargs["clients"]
757
if "use_ipv6" in kwargs:
758
if not kwargs["use_ipv6"]:
759
self.address_family = socket.AF_INET
760
del kwargs["use_ipv6"]
762
super(IPv6_TCPServer, self).__init__(*args, **kwargs)
1108
763
def server_bind(self):
1109
764
"""This overrides the normal server_bind() function
1110
765
to bind to an interface if one was specified, and also NOT to
1111
766
bind to an address or port if they were not specified."""
1112
if self.interface is not None:
1113
if SO_BINDTODEVICE is None:
1114
logger.error(u"SO_BINDTODEVICE does not exist;"
1115
u" cannot bind to interface %s",
1119
self.socket.setsockopt(socket.SOL_SOCKET,
1123
except socket.error, error:
1124
if error[0] == errno.EPERM:
1125
logger.error(u"No permission to"
1126
u" bind to interface %s",
1128
elif error[0] == errno.ENOPROTOOPT:
1129
logger.error(u"SO_BINDTODEVICE not available;"
1130
u" cannot bind to interface %s",
767
if self.settings["interface"]:
768
# 25 is from /usr/include/asm-i486/socket.h
769
SO_BINDTODEVICE = getattr(socket, "SO_BINDTODEVICE", 25)
771
self.socket.setsockopt(socket.SOL_SOCKET,
773
self.settings["interface"])
774
except socket.error, error:
775
if error[0] == errno.EPERM:
776
logger.error(u"No permission to"
777
u" bind to interface %s",
778
self.settings["interface"])
1134
781
# Only bind(2) the socket if we really need to.
1135
782
if self.server_address[0] or self.server_address[1]:
1136
783
if not self.server_address[0]:
1137
784
if self.address_family == socket.AF_INET6:
1138
any_address = u"::" # in6addr_any
785
any_address = "::" # in6addr_any
1140
787
any_address = socket.INADDR_ANY
1141
788
self.server_address = (any_address,