/mandos/release

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/release

« back to all changes in this revision

Viewing changes to mandos

  • Committer: teddy at recompile
  • Date: 2020-04-08 18:40:10 UTC
  • Revision ID: teddy@recompile.se-20200408184010-lvs5alrq2gqcpb12
Tags: version-1.8.11-1
Version 1.8.11-1

* Makefile (version): Change to "1.8.11".
* NEWS (Version 1.8.11): Add new entry.
* debian/changelog (1.8.11-1): - '' -

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
# "AvahiService" class, and some lines in "main".
12
12
#
13
13
# Everything else is
14
 
# Copyright © 2008-2020 Teddy Hogeborn
15
 
# Copyright © 2008-2020 Björn Påhlsson
 
14
# Copyright © 2008-2019 Teddy Hogeborn
 
15
# Copyright © 2008-2019 Björn Påhlsson
16
16
#
17
17
# This file is part of Mandos.
18
18
#
143
143
if sys.version_info < (3, 2):
144
144
    configparser.Configparser = configparser.SafeConfigParser
145
145
 
146
 
version = "1.8.14"
 
146
version = "1.8.11"
147
147
stored_state_file = "clients.pickle"
148
148
 
149
149
logger = logging.getLogger()
189
189
        facility=logging.handlers.SysLogHandler.LOG_DAEMON,
190
190
        address="/dev/log"))
191
191
    syslogger.setFormatter(logging.Formatter
192
 
                           ("Mandos [%(process)d]: %(levelname)s:"
193
 
                            " %(message)s"))
 
192
                           ('Mandos [%(process)d]: %(levelname)s:'
 
193
                            ' %(message)s'))
194
194
    logger.addHandler(syslogger)
195
195
 
196
196
    if debug:
197
197
        console = logging.StreamHandler()
198
 
        console.setFormatter(logging.Formatter("%(asctime)s %(name)s"
199
 
                                               " [%(process)d]:"
200
 
                                               " %(levelname)s:"
201
 
                                               " %(message)s"))
 
198
        console.setFormatter(logging.Formatter('%(asctime)s %(name)s'
 
199
                                               ' [%(process)d]:'
 
200
                                               ' %(levelname)s:'
 
201
                                               ' %(message)s'))
202
202
        logger.addHandler(console)
203
203
    logger.setLevel(level)
204
204
 
224
224
        except OSError as e:
225
225
            if e.errno != errno.ENOENT:
226
226
                raise
227
 
        self.gnupgargs = ["--batch",
228
 
                          "--homedir", self.tempdir,
229
 
                          "--force-mdc",
230
 
                          "--quiet"]
 
227
        self.gnupgargs = ['--batch',
 
228
                          '--homedir', self.tempdir,
 
229
                          '--force-mdc',
 
230
                          '--quiet']
231
231
        # Only GPG version 1 has the --no-use-agent option.
232
232
        if self.gpg == b"gpg" or self.gpg.endswith(b"/gpg"):
233
233
            self.gnupgargs.append("--no-use-agent")
272
272
                dir=self.tempdir) as passfile:
273
273
            passfile.write(passphrase)
274
274
            passfile.flush()
275
 
            proc = subprocess.Popen([self.gpg, "--symmetric",
276
 
                                     "--passphrase-file",
 
275
            proc = subprocess.Popen([self.gpg, '--symmetric',
 
276
                                     '--passphrase-file',
277
277
                                     passfile.name]
278
278
                                    + self.gnupgargs,
279
279
                                    stdin=subprocess.PIPE,
290
290
                dir=self.tempdir) as passfile:
291
291
            passfile.write(passphrase)
292
292
            passfile.flush()
293
 
            proc = subprocess.Popen([self.gpg, "--decrypt",
294
 
                                     "--passphrase-file",
 
293
            proc = subprocess.Popen([self.gpg, '--decrypt',
 
294
                                     '--passphrase-file',
295
295
                                     passfile.name]
296
296
                                    + self.gnupgargs,
297
297
                                    stdin=subprocess.PIPE,
350
350
    Attributes:
351
351
    interface: integer; avahi.IF_UNSPEC or an interface index.
352
352
               Used to optionally bind to the specified interface.
353
 
    name: string; Example: "Mandos"
354
 
    type: string; Example: "_mandos._tcp".
 
353
    name: string; Example: 'Mandos'
 
354
    type: string; Example: '_mandos._tcp'.
355
355
     See <https://www.iana.org/assignments/service-names-port-numbers>
356
356
    port: integer; what port to announce
357
357
    TXT: list of strings; TXT record for the service
435
435
                avahi.DBUS_INTERFACE_ENTRY_GROUP)
436
436
        self.entry_group_state_changed_match = (
437
437
            self.group.connect_to_signal(
438
 
                "StateChanged", self.entry_group_state_changed))
 
438
                'StateChanged', self.entry_group_state_changed))
439
439
        logger.debug("Adding Zeroconf service '%s' of type '%s' ...",
440
440
                     self.name, self.type)
441
441
        self.group.AddService(
524
524
class AvahiServiceToSyslog(AvahiService):
525
525
    def rename(self, *args, **kwargs):
526
526
        """Add the new name to the syslog messages"""
527
 
        ret = super(AvahiServiceToSyslog, self).rename(*args,
528
 
                                                       **kwargs)
 
527
        ret = super(AvahiServiceToSyslog, self).rename(*args, **kwargs)
529
528
        syslogger.setFormatter(logging.Formatter(
530
 
            "Mandos ({}) [%(process)d]: %(levelname)s: %(message)s"
 
529
            'Mandos ({}) [%(process)d]: %(levelname)s: %(message)s'
531
530
            .format(self.name)))
532
531
        return ret
533
532
 
563
562
    OPENPGP_FMT_RAW = 0         # gnutls/openpgp.h
564
563
 
565
564
    # Types
566
 
    class _session_int(ctypes.Structure):
 
565
    class session_int(ctypes.Structure):
567
566
        _fields_ = []
568
 
    session_t = ctypes.POINTER(_session_int)
 
567
    session_t = ctypes.POINTER(session_int)
569
568
 
570
569
    class certificate_credentials_st(ctypes.Structure):
571
570
        _fields_ = []
574
573
    certificate_type_t = ctypes.c_int
575
574
 
576
575
    class datum_t(ctypes.Structure):
577
 
        _fields_ = [("data", ctypes.POINTER(ctypes.c_ubyte)),
578
 
                    ("size", ctypes.c_uint)]
 
576
        _fields_ = [('data', ctypes.POINTER(ctypes.c_ubyte)),
 
577
                    ('size', ctypes.c_uint)]
579
578
 
580
 
    class _openpgp_crt_int(ctypes.Structure):
 
579
    class openpgp_crt_int(ctypes.Structure):
581
580
        _fields_ = []
582
 
    openpgp_crt_t = ctypes.POINTER(_openpgp_crt_int)
 
581
    openpgp_crt_t = ctypes.POINTER(openpgp_crt_int)
583
582
    openpgp_crt_fmt_t = ctypes.c_int  # gnutls/openpgp.h
584
583
    log_func = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p)
585
584
    credentials_type_t = ctypes.c_int
594
593
            # gnutls.strerror()
595
594
            self.code = code
596
595
            if message is None and code is not None:
597
 
                message = gnutls.strerror(code).decode(
598
 
                    "utf-8", errors="replace")
 
596
                message = gnutls.strerror(code)
599
597
            return super(gnutls.Error, self).__init__(
600
598
                message, *args)
601
599
 
602
600
    class CertificateSecurityError(Error):
603
601
        pass
604
602
 
605
 
    class PointerTo:
606
 
        def __init__(self, cls):
607
 
            self.cls = cls
608
 
 
609
 
        def from_param(self, obj):
610
 
            if not isinstance(obj, self.cls):
611
 
                raise TypeError("Not of type {}: {!r}"
612
 
                                .format(self.cls.__name__, obj))
613
 
            return ctypes.byref(obj.from_param(obj))
614
 
 
615
 
    class CastToVoidPointer:
616
 
        def __init__(self, cls):
617
 
            self.cls = cls
618
 
 
619
 
        def from_param(self, obj):
620
 
            if not isinstance(obj, self.cls):
621
 
                raise TypeError("Not of type {}: {!r}"
622
 
                                .format(self.cls.__name__, obj))
623
 
            return ctypes.cast(obj.from_param(obj), ctypes.c_void_p)
624
 
 
625
 
    class With_from_param:
626
 
        @classmethod
627
 
        def from_param(cls, obj):
628
 
            return obj._as_parameter_
629
 
 
630
603
    # Classes
631
 
    class Credentials(With_from_param):
 
604
    class Credentials:
632
605
        def __init__(self):
633
 
            self._as_parameter_ = gnutls.certificate_credentials_t()
634
 
            gnutls.certificate_allocate_credentials(self)
 
606
            self._c_object = gnutls.certificate_credentials_t()
 
607
            gnutls.certificate_allocate_credentials(
 
608
                ctypes.byref(self._c_object))
635
609
            self.type = gnutls.CRD_CERTIFICATE
636
610
 
637
611
        def __del__(self):
638
 
            gnutls.certificate_free_credentials(self)
 
612
            gnutls.certificate_free_credentials(self._c_object)
639
613
 
640
 
    class ClientSession(With_from_param):
 
614
    class ClientSession:
641
615
        def __init__(self, socket, credentials=None):
642
 
            self._as_parameter_ = gnutls.session_t()
 
616
            self._c_object = gnutls.session_t()
643
617
            gnutls_flags = gnutls.CLIENT
644
618
            if gnutls.check_version(b"3.5.6"):
645
619
                gnutls_flags |= gnutls.NO_TICKETS
646
620
            if gnutls.has_rawpk:
647
621
                gnutls_flags |= gnutls.ENABLE_RAWPK
648
 
            gnutls.init(self, gnutls_flags)
 
622
            gnutls.init(ctypes.byref(self._c_object), gnutls_flags)
649
623
            del gnutls_flags
650
 
            gnutls.set_default_priority(self)
651
 
            gnutls.transport_set_ptr(self, socket.fileno())
652
 
            gnutls.handshake_set_private_extensions(self, True)
 
624
            gnutls.set_default_priority(self._c_object)
 
625
            gnutls.transport_set_ptr(self._c_object, socket.fileno())
 
626
            gnutls.handshake_set_private_extensions(self._c_object,
 
627
                                                    True)
653
628
            self.socket = socket
654
629
            if credentials is None:
655
630
                credentials = gnutls.Credentials()
656
 
            gnutls.credentials_set(self, credentials.type,
657
 
                                   credentials)
 
631
            gnutls.credentials_set(self._c_object, credentials.type,
 
632
                                   ctypes.cast(credentials._c_object,
 
633
                                               ctypes.c_void_p))
658
634
            self.credentials = credentials
659
635
 
660
636
        def __del__(self):
661
 
            gnutls.deinit(self)
 
637
            gnutls.deinit(self._c_object)
662
638
 
663
639
        def handshake(self):
664
 
            return gnutls.handshake(self)
 
640
            return gnutls.handshake(self._c_object)
665
641
 
666
642
        def send(self, data):
667
643
            data = bytes(data)
668
644
            data_len = len(data)
669
645
            while data_len > 0:
670
 
                data_len -= gnutls.record_send(self, data[-data_len:],
 
646
                data_len -= gnutls.record_send(self._c_object,
 
647
                                               data[-data_len:],
671
648
                                               data_len)
672
649
 
673
650
        def bye(self):
674
 
            return gnutls.bye(self, gnutls.SHUT_RDWR)
 
651
            return gnutls.bye(self._c_object, gnutls.SHUT_RDWR)
675
652
 
676
653
    # Error handling functions
677
654
    def _error_code(result):
678
655
        """A function to raise exceptions on errors, suitable
679
 
        for the "restype" attribute on ctypes functions"""
680
 
        if result >= gnutls.E_SUCCESS:
 
656
        for the 'restype' attribute on ctypes functions"""
 
657
        if result >= 0:
681
658
            return result
682
659
        if result == gnutls.E_NO_CERTIFICATE_FOUND:
683
660
            raise gnutls.CertificateSecurityError(code=result)
684
661
        raise gnutls.Error(code=result)
685
662
 
686
 
    def _retry_on_error(result, func, arguments,
687
 
                        _error_code=_error_code):
 
663
    def _retry_on_error(result, func, arguments):
688
664
        """A function to retry on some errors, suitable
689
 
        for the "errcheck" attribute on ctypes functions"""
690
 
        while result < gnutls.E_SUCCESS:
 
665
        for the 'errcheck' attribute on ctypes functions"""
 
666
        while result < 0:
691
667
            if result not in (gnutls.E_INTERRUPTED, gnutls.E_AGAIN):
692
668
                return _error_code(result)
693
669
            result = func(*arguments)
698
674
 
699
675
    # Functions
700
676
    priority_set_direct = _library.gnutls_priority_set_direct
701
 
    priority_set_direct.argtypes = [ClientSession, ctypes.c_char_p,
 
677
    priority_set_direct.argtypes = [session_t, ctypes.c_char_p,
702
678
                                    ctypes.POINTER(ctypes.c_char_p)]
703
679
    priority_set_direct.restype = _error_code
704
680
 
705
681
    init = _library.gnutls_init
706
 
    init.argtypes = [PointerTo(ClientSession), ctypes.c_int]
 
682
    init.argtypes = [ctypes.POINTER(session_t), ctypes.c_int]
707
683
    init.restype = _error_code
708
684
 
709
685
    set_default_priority = _library.gnutls_set_default_priority
710
 
    set_default_priority.argtypes = [ClientSession]
 
686
    set_default_priority.argtypes = [session_t]
711
687
    set_default_priority.restype = _error_code
712
688
 
713
689
    record_send = _library.gnutls_record_send
714
 
    record_send.argtypes = [ClientSession, ctypes.c_void_p,
 
690
    record_send.argtypes = [session_t, ctypes.c_void_p,
715
691
                            ctypes.c_size_t]
716
692
    record_send.restype = ctypes.c_ssize_t
717
693
    record_send.errcheck = _retry_on_error
719
695
    certificate_allocate_credentials = (
720
696
        _library.gnutls_certificate_allocate_credentials)
721
697
    certificate_allocate_credentials.argtypes = [
722
 
        PointerTo(Credentials)]
 
698
        ctypes.POINTER(certificate_credentials_t)]
723
699
    certificate_allocate_credentials.restype = _error_code
724
700
 
725
701
    certificate_free_credentials = (
726
702
        _library.gnutls_certificate_free_credentials)
727
 
    certificate_free_credentials.argtypes = [Credentials]
 
703
    certificate_free_credentials.argtypes = [
 
704
        certificate_credentials_t]
728
705
    certificate_free_credentials.restype = None
729
706
 
730
707
    handshake_set_private_extensions = (
731
708
        _library.gnutls_handshake_set_private_extensions)
732
 
    handshake_set_private_extensions.argtypes = [ClientSession,
 
709
    handshake_set_private_extensions.argtypes = [session_t,
733
710
                                                 ctypes.c_int]
734
711
    handshake_set_private_extensions.restype = None
735
712
 
736
713
    credentials_set = _library.gnutls_credentials_set
737
 
    credentials_set.argtypes = [ClientSession, credentials_type_t,
738
 
                                CastToVoidPointer(Credentials)]
 
714
    credentials_set.argtypes = [session_t, credentials_type_t,
 
715
                                ctypes.c_void_p]
739
716
    credentials_set.restype = _error_code
740
717
 
741
718
    strerror = _library.gnutls_strerror
743
720
    strerror.restype = ctypes.c_char_p
744
721
 
745
722
    certificate_type_get = _library.gnutls_certificate_type_get
746
 
    certificate_type_get.argtypes = [ClientSession]
 
723
    certificate_type_get.argtypes = [session_t]
747
724
    certificate_type_get.restype = _error_code
748
725
 
749
726
    certificate_get_peers = _library.gnutls_certificate_get_peers
750
 
    certificate_get_peers.argtypes = [ClientSession,
 
727
    certificate_get_peers.argtypes = [session_t,
751
728
                                      ctypes.POINTER(ctypes.c_uint)]
752
729
    certificate_get_peers.restype = ctypes.POINTER(datum_t)
753
730
 
760
737
    global_set_log_function.restype = None
761
738
 
762
739
    deinit = _library.gnutls_deinit
763
 
    deinit.argtypes = [ClientSession]
 
740
    deinit.argtypes = [session_t]
764
741
    deinit.restype = None
765
742
 
766
743
    handshake = _library.gnutls_handshake
767
 
    handshake.argtypes = [ClientSession]
768
 
    handshake.restype = ctypes.c_int
 
744
    handshake.argtypes = [session_t]
 
745
    handshake.restype = _error_code
769
746
    handshake.errcheck = _retry_on_error
770
747
 
771
748
    transport_set_ptr = _library.gnutls_transport_set_ptr
772
 
    transport_set_ptr.argtypes = [ClientSession, transport_ptr_t]
 
749
    transport_set_ptr.argtypes = [session_t, transport_ptr_t]
773
750
    transport_set_ptr.restype = None
774
751
 
775
752
    bye = _library.gnutls_bye
776
 
    bye.argtypes = [ClientSession, close_request_t]
777
 
    bye.restype = ctypes.c_int
 
753
    bye.argtypes = [session_t, close_request_t]
 
754
    bye.restype = _error_code
778
755
    bye.errcheck = _retry_on_error
779
756
 
780
757
    check_version = _library.gnutls_check_version
797
774
 
798
775
        x509_crt_fmt_t = ctypes.c_int
799
776
 
800
 
        # All the function declarations below are from
801
 
        # gnutls/abstract.h
 
777
        # All the function declarations below are from gnutls/abstract.h
802
778
        pubkey_init = _library.gnutls_pubkey_init
803
779
        pubkey_init.argtypes = [ctypes.POINTER(pubkey_t)]
804
780
        pubkey_init.restype = _error_code
818
794
        pubkey_deinit.argtypes = [pubkey_t]
819
795
        pubkey_deinit.restype = None
820
796
    else:
821
 
        # All the function declarations below are from
822
 
        # gnutls/openpgp.h
 
797
        # All the function declarations below are from gnutls/openpgp.h
823
798
 
824
799
        openpgp_crt_init = _library.gnutls_openpgp_crt_init
825
800
        openpgp_crt_init.argtypes = [ctypes.POINTER(openpgp_crt_t)]
831
806
                                       openpgp_crt_fmt_t]
832
807
        openpgp_crt_import.restype = _error_code
833
808
 
834
 
        openpgp_crt_verify_self = \
835
 
            _library.gnutls_openpgp_crt_verify_self
836
 
        openpgp_crt_verify_self.argtypes = [
837
 
            openpgp_crt_t,
838
 
            ctypes.c_uint,
839
 
            ctypes.POINTER(ctypes.c_uint),
840
 
        ]
 
809
        openpgp_crt_verify_self = _library.gnutls_openpgp_crt_verify_self
 
810
        openpgp_crt_verify_self.argtypes = [openpgp_crt_t, ctypes.c_uint,
 
811
                                            ctypes.POINTER(ctypes.c_uint)]
841
812
        openpgp_crt_verify_self.restype = _error_code
842
813
 
843
814
        openpgp_crt_deinit = _library.gnutls_openpgp_crt_deinit
854
825
 
855
826
    if check_version(b"3.6.4"):
856
827
        certificate_type_get2 = _library.gnutls_certificate_type_get2
857
 
        certificate_type_get2.argtypes = [ClientSession, ctypes.c_int]
 
828
        certificate_type_get2.argtypes = [session_t, ctypes.c_int]
858
829
        certificate_type_get2.restype = _error_code
859
830
 
860
831
    # Remove non-public functions
876
847
    """A representation of a client host served by this server.
877
848
 
878
849
    Attributes:
879
 
    approved:   bool(); None if not yet approved/disapproved
 
850
    approved:   bool(); 'None' if not yet approved/disapproved
880
851
    approval_delay: datetime.timedelta(); Time to wait for approval
881
852
    approval_duration: datetime.timedelta(); Duration of one approval
882
853
    checker: multiprocessing.Process(); a running checker process used
883
 
             to see if the client lives. None if no process is
 
854
             to see if the client lives. 'None' if no process is
884
855
             running.
885
856
    checker_callback_tag: a GLib event source tag, or None
886
857
    checker_command: string; External command which is run to check
1242
1213
        func._dbus_name = func.__name__
1243
1214
        if func._dbus_name.endswith("_dbus_property"):
1244
1215
            func._dbus_name = func._dbus_name[:-14]
1245
 
        func._dbus_get_args_options = {"byte_arrays": byte_arrays}
 
1216
        func._dbus_get_args_options = {'byte_arrays': byte_arrays}
1246
1217
        return func
1247
1218
 
1248
1219
    return decorator
1337
1308
 
1338
1309
    @dbus.service.method(dbus.INTROSPECTABLE_IFACE,
1339
1310
                         out_signature="s",
1340
 
                         path_keyword="object_path",
1341
 
                         connection_keyword="connection")
 
1311
                         path_keyword='object_path',
 
1312
                         connection_keyword='connection')
1342
1313
    def Introspect(self, object_path, connection):
1343
1314
        """Overloading of standard D-Bus method.
1344
1315
 
1497
1468
 
1498
1469
    @dbus.service.method(dbus.INTROSPECTABLE_IFACE,
1499
1470
                         out_signature="s",
1500
 
                         path_keyword="object_path",
1501
 
                         connection_keyword="connection")
 
1471
                         path_keyword='object_path',
 
1472
                         connection_keyword='connection')
1502
1473
    def Introspect(self, object_path, connection):
1503
1474
        """Overloading of standard D-Bus method.
1504
1475
 
1599
1570
 
1600
1571
    @dbus.service.method(dbus.INTROSPECTABLE_IFACE,
1601
1572
                         out_signature="s",
1602
 
                         path_keyword="object_path",
1603
 
                         connection_keyword="connection")
 
1573
                         path_keyword='object_path',
 
1574
                         connection_keyword='connection')
1604
1575
    def Introspect(self, object_path, connection):
1605
1576
        """Overloading of standard D-Bus method.
1606
1577
 
2272
2243
class ProxyClient:
2273
2244
    def __init__(self, child_pipe, key_id, fpr, address):
2274
2245
        self._pipe = child_pipe
2275
 
        self._pipe.send(("init", key_id, fpr, address))
 
2246
        self._pipe.send(('init', key_id, fpr, address))
2276
2247
        if not self._pipe.recv():
2277
2248
            raise KeyError(key_id or fpr)
2278
2249
 
2279
2250
    def __getattribute__(self, name):
2280
 
        if name == "_pipe":
 
2251
        if name == '_pipe':
2281
2252
            return super(ProxyClient, self).__getattribute__(name)
2282
 
        self._pipe.send(("getattr", name))
 
2253
        self._pipe.send(('getattr', name))
2283
2254
        data = self._pipe.recv()
2284
 
        if data[0] == "data":
 
2255
        if data[0] == 'data':
2285
2256
            return data[1]
2286
 
        if data[0] == "function":
 
2257
        if data[0] == 'function':
2287
2258
 
2288
2259
            def func(*args, **kwargs):
2289
 
                self._pipe.send(("funcall", name, args, kwargs))
 
2260
                self._pipe.send(('funcall', name, args, kwargs))
2290
2261
                return self._pipe.recv()[1]
2291
2262
 
2292
2263
            return func
2293
2264
 
2294
2265
    def __setattr__(self, name, value):
2295
 
        if name == "_pipe":
 
2266
        if name == '_pipe':
2296
2267
            return super(ProxyClient, self).__setattr__(name, value)
2297
 
        self._pipe.send(("setattr", name, value))
 
2268
        self._pipe.send(('setattr', name, value))
2298
2269
 
2299
2270
 
2300
2271
class ClientHandler(socketserver.BaseRequestHandler, object):
2312
2283
 
2313
2284
            session = gnutls.ClientSession(self.request)
2314
2285
 
2315
 
            # priority = ":".join(("NONE", "+VERS-TLS1.1",
 
2286
            # priority = ':'.join(("NONE", "+VERS-TLS1.1",
2316
2287
            #                       "+AES-256-CBC", "+SHA1",
2317
2288
            #                       "+COMP-NULL", "+CTYPE-OPENPGP",
2318
2289
            #                       "+DHE-DSS"))
2320
2291
            priority = self.server.gnutls_priority
2321
2292
            if priority is None:
2322
2293
                priority = "NORMAL"
2323
 
            gnutls.priority_set_direct(session,
2324
 
                                       priority.encode("utf-8"), None)
 
2294
            gnutls.priority_set_direct(session._c_object,
 
2295
                                       priority.encode("utf-8"),
 
2296
                                       None)
2325
2297
 
2326
2298
            # Start communication using the Mandos protocol
2327
2299
            # Get protocol number
2354
2326
                    except (TypeError, gnutls.Error) as error:
2355
2327
                        logger.warning("Bad certificate: %s", error)
2356
2328
                        return
2357
 
                    logger.debug("Key ID: %s",
2358
 
                                 key_id.decode("utf-8",
2359
 
                                               errors="replace"))
 
2329
                    logger.debug("Key ID: %s", key_id)
2360
2330
 
2361
2331
                else:
2362
2332
                    key_id = b""
2454
2424
    def peer_certificate(session):
2455
2425
        "Return the peer's certificate as a bytestring"
2456
2426
        try:
2457
 
            cert_type = gnutls.certificate_type_get2(
2458
 
                session, gnutls.CTYPE_PEERS)
 
2427
            cert_type = gnutls.certificate_type_get2(session._c_object,
 
2428
                                                     gnutls.CTYPE_PEERS)
2459
2429
        except AttributeError:
2460
 
            cert_type = gnutls.certificate_type_get(session)
 
2430
            cert_type = gnutls.certificate_type_get(session._c_object)
2461
2431
        if gnutls.has_rawpk:
2462
2432
            valid_cert_types = frozenset((gnutls.CRT_RAWPK,))
2463
2433
        else:
2470
2440
            return b""
2471
2441
        list_size = ctypes.c_uint(1)
2472
2442
        cert_list = (gnutls.certificate_get_peers
2473
 
                     (session, ctypes.byref(list_size)))
 
2443
                     (session._c_object, ctypes.byref(list_size)))
2474
2444
        if not bool(cert_list) and list_size.value != 0:
2475
2445
            raise gnutls.Error("error getting peer certificate")
2476
2446
        if list_size.value == 0:
2498
2468
        buf = ctypes.create_string_buffer(32)
2499
2469
        buf_len = ctypes.c_size_t(len(buf))
2500
2470
        # Get the key ID from the raw public key into the buffer
2501
 
        gnutls.pubkey_get_key_id(
2502
 
            pubkey,
2503
 
            gnutls.KEYID_USE_SHA256,
2504
 
            ctypes.cast(ctypes.byref(buf),
2505
 
                        ctypes.POINTER(ctypes.c_ubyte)),
2506
 
            ctypes.byref(buf_len))
 
2471
        gnutls.pubkey_get_key_id(pubkey,
 
2472
                                 gnutls.KEYID_USE_SHA256,
 
2473
                                 ctypes.cast(ctypes.byref(buf),
 
2474
                                             ctypes.POINTER(ctypes.c_ubyte)),
 
2475
                                 ctypes.byref(buf_len))
2507
2476
        # Deinit the certificate
2508
2477
        gnutls.pubkey_deinit(pubkey)
2509
2478
 
2590
2559
 
2591
2560
class IPv6_TCPServer(MultiprocessingMixInWithPipe,
2592
2561
                     socketserver.TCPServer):
2593
 
    """IPv6-capable TCP server.  Accepts None as address and/or port
 
2562
    """IPv6-capable TCP server.  Accepts 'None' as address and/or port
2594
2563
 
2595
2564
    Attributes:
2596
2565
        enabled:        Boolean; whether this server is activated yet
2748
2717
        request = parent_pipe.recv()
2749
2718
        command = request[0]
2750
2719
 
2751
 
        if command == "init":
 
2720
        if command == 'init':
2752
2721
            key_id = request[1].decode("ascii")
2753
2722
            fpr = request[2].decode("ascii")
2754
2723
            address = request[3]
2755
2724
 
2756
2725
            for c in self.clients.values():
2757
 
                if key_id == ("E3B0C44298FC1C149AFBF4C8996FB924"
2758
 
                              "27AE41E4649B934CA495991B7852B855"):
 
2726
                if key_id == "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855":
2759
2727
                    continue
2760
2728
                if key_id and c.key_id == key_id:
2761
2729
                    client = c
2784
2752
            # remove the old hook in favor of the new above hook on
2785
2753
            # same fileno
2786
2754
            return False
2787
 
        if command == "funcall":
 
2755
        if command == 'funcall':
2788
2756
            funcname = request[1]
2789
2757
            args = request[2]
2790
2758
            kwargs = request[3]
2791
2759
 
2792
 
            parent_pipe.send(("data", getattr(client_object,
 
2760
            parent_pipe.send(('data', getattr(client_object,
2793
2761
                                              funcname)(*args,
2794
2762
                                                        **kwargs)))
2795
2763
 
2796
 
        if command == "getattr":
 
2764
        if command == 'getattr':
2797
2765
            attrname = request[1]
2798
2766
            if isinstance(client_object.__getattribute__(attrname),
2799
2767
                          collections.abc.Callable):
2800
 
                parent_pipe.send(("function", ))
 
2768
                parent_pipe.send(('function', ))
2801
2769
            else:
2802
2770
                parent_pipe.send((
2803
 
                    "data", client_object.__getattribute__(attrname)))
 
2771
                    'data', client_object.__getattribute__(attrname)))
2804
2772
 
2805
 
        if command == "setattr":
 
2773
        if command == 'setattr':
2806
2774
            attrname = request[1]
2807
2775
            value = request[2]
2808
2776
            setattr(client_object, attrname, value)
2813
2781
def rfc3339_duration_to_delta(duration):
2814
2782
    """Parse an RFC 3339 "duration" and return a datetime.timedelta
2815
2783
 
2816
 
    >>> timedelta = datetime.timedelta
2817
 
    >>> rfc3339_duration_to_delta("P7D") == timedelta(7)
2818
 
    True
2819
 
    >>> rfc3339_duration_to_delta("PT60S") == timedelta(0, 60)
2820
 
    True
2821
 
    >>> rfc3339_duration_to_delta("PT60M") == timedelta(0, 3600)
2822
 
    True
2823
 
    >>> rfc3339_duration_to_delta("PT24H") == timedelta(1)
2824
 
    True
2825
 
    >>> rfc3339_duration_to_delta("P1W") == timedelta(7)
2826
 
    True
2827
 
    >>> rfc3339_duration_to_delta("PT5M30S") == timedelta(0, 330)
2828
 
    True
2829
 
    >>> rfc3339_duration_to_delta("P1DT3M20S") == timedelta(1, 200)
2830
 
    True
2831
 
    >>> del timedelta
 
2784
    >>> rfc3339_duration_to_delta("P7D") == datetime.timedelta(7)
 
2785
    True
 
2786
    >>> rfc3339_duration_to_delta("PT60S") == datetime.timedelta(0, 60)
 
2787
    True
 
2788
    >>> rfc3339_duration_to_delta("PT60M") == datetime.timedelta(0, 3600)
 
2789
    True
 
2790
    >>> rfc3339_duration_to_delta("PT24H") == datetime.timedelta(1)
 
2791
    True
 
2792
    >>> rfc3339_duration_to_delta("P1W") == datetime.timedelta(7)
 
2793
    True
 
2794
    >>> rfc3339_duration_to_delta("PT5M30S") == datetime.timedelta(0, 330)
 
2795
    True
 
2796
    >>> rfc3339_duration_to_delta("P1DT3M20S") == datetime.timedelta(1, 200)
 
2797
    True
2832
2798
    """
2833
2799
 
2834
2800
    # Parsing an RFC 3339 duration with regular expressions is not
2914
2880
def string_to_delta(interval):
2915
2881
    """Parse a string and return a datetime.timedelta
2916
2882
 
2917
 
    >>> string_to_delta("7d") == datetime.timedelta(7)
2918
 
    True
2919
 
    >>> string_to_delta("60s") == datetime.timedelta(0, 60)
2920
 
    True
2921
 
    >>> string_to_delta("60m") == datetime.timedelta(0, 3600)
2922
 
    True
2923
 
    >>> string_to_delta("24h") == datetime.timedelta(1)
2924
 
    True
2925
 
    >>> string_to_delta("1w") == datetime.timedelta(7)
2926
 
    True
2927
 
    >>> string_to_delta("5m 30s") == datetime.timedelta(0, 330)
 
2883
    >>> string_to_delta('7d') == datetime.timedelta(7)
 
2884
    True
 
2885
    >>> string_to_delta('60s') == datetime.timedelta(0, 60)
 
2886
    True
 
2887
    >>> string_to_delta('60m') == datetime.timedelta(0, 3600)
 
2888
    True
 
2889
    >>> string_to_delta('24h') == datetime.timedelta(1)
 
2890
    True
 
2891
    >>> string_to_delta('1w') == datetime.timedelta(7)
 
2892
    True
 
2893
    >>> string_to_delta('5m 30s') == datetime.timedelta(0, 330)
2928
2894
    True
2929
2895
    """
2930
2896
 
3134
3100
 
3135
3101
    if server_settings["servicename"] != "Mandos":
3136
3102
        syslogger.setFormatter(
3137
 
            logging.Formatter("Mandos ({}) [%(process)d]:"
3138
 
                              " %(levelname)s: %(message)s".format(
 
3103
            logging.Formatter('Mandos ({}) [%(process)d]:'
 
3104
                              ' %(levelname)s: %(message)s'.format(
3139
3105
                                  server_settings["servicename"])))
3140
3106
 
3141
3107
    # Parse config file with clients
3201
3167
 
3202
3168
        @gnutls.log_func
3203
3169
        def debug_gnutls(level, string):
3204
 
            logger.debug("GnuTLS: %s",
3205
 
                         string[:-1].decode("utf-8",
3206
 
                                            errors="replace"))
 
3170
            logger.debug("GnuTLS: %s", string[:-1])
3207
3171
 
3208
3172
        gnutls.global_set_log_function(debug_gnutls)
3209
3173
 
3584
3548
 
3585
3549
        try:
3586
3550
            with tempfile.NamedTemporaryFile(
3587
 
                    mode="wb",
 
3551
                    mode='wb',
3588
3552
                    suffix=".pickle",
3589
 
                    prefix="clients-",
 
3553
                    prefix='clients-',
3590
3554
                    dir=os.path.dirname(stored_state_path),
3591
3555
                    delete=False) as stored_state:
3592
3556
                pickle.dump((clients, client_settings), stored_state,
3679
3643
 
3680
3644
def should_only_run_tests():
3681
3645
    parser = argparse.ArgumentParser(add_help=False)
3682
 
    parser.add_argument("--check", action="store_true")
 
3646
    parser.add_argument("--check", action='store_true')
3683
3647
    args, unknown_args = parser.parse_known_args()
3684
3648
    run_tests = args.check
3685
3649
    if run_tests:
3693
3657
    tests.addTests(doctest.DocTestSuite())
3694
3658
    return tests
3695
3659
 
3696
 
if __name__ == "__main__":
 
3660
if __name__ == '__main__':
3697
3661
    try:
3698
3662
        if should_only_run_tests():
3699
3663
            # Call using ./mandos --check [--verbose]