/mandos/trunk

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

« back to all changes in this revision

Viewing changes to mandos

  • Committer: teddy at recompile
  • Date: 2020-02-05 21:39:28 UTC
  • Revision ID: teddy@recompile.se-20200205213928-vpvt0fwfg47ikv6f
Allow users to alter ask-password-mandos.service

If a user uses dracut with systemd and wishes to modify the options
passed to password-agent(8mandos) or mandos-client(8mandos), they
should be able to do so by simply creating a file
/etc/systemd/system/ask-password-mandos.service.d/override.conf,
containing, for instance:

[Service]
Environment=MANDOS_CLIENT_OPTIONS=--debug

Adding PASSWORD_AGENT_OPTIONS should also be possible (but should not
normally be needed).

* dracut-module/ask-password-mandos.service ([Service]/ExecStart): Add
  $PASSWORD_AGENT_OPTIONS before "--" and "$MANDOS_CLIENT_OPTIONS" to
  end of line.
* dracut-module/module-setup.sh (install): Install all files named
  /etc/systemd/system/ask-password-mandos.service.d/*.conf if any
  exists.  Also add --dh-params before $MANDOS_CLIENT_OPTIONS instead
  of at end of line.

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
#
79
79
import codecs
80
80
import unittest
81
81
import random
82
 
import shlex
83
82
 
84
83
import dbus
85
84
import dbus.service
95
94
    __metaclass__ = type
96
95
    str = unicode
97
96
 
98
 
# Add collections.abc.Callable if it does not exist
99
 
try:
100
 
    collections.abc.Callable
101
 
except AttributeError:
102
 
    class abc:
103
 
        Callable = collections.Callable
104
 
    collections.abc = abc
105
 
    del abc
106
 
 
107
 
# Add shlex.quote if it does not exist
108
 
try:
109
 
    shlex.quote
110
 
except AttributeError:
111
 
    shlex.quote = re.escape
112
 
 
113
97
# Show warnings by default
114
98
if not sys.warnoptions:
115
99
    import warnings
143
127
if sys.version_info < (3, 2):
144
128
    configparser.Configparser = configparser.SafeConfigParser
145
129
 
146
 
version = "1.8.14"
 
130
version = "1.8.9"
147
131
stored_state_file = "clients.pickle"
148
132
 
149
133
logger = logging.getLogger()
189
173
        facility=logging.handlers.SysLogHandler.LOG_DAEMON,
190
174
        address="/dev/log"))
191
175
    syslogger.setFormatter(logging.Formatter
192
 
                           ("Mandos [%(process)d]: %(levelname)s:"
193
 
                            " %(message)s"))
 
176
                           ('Mandos [%(process)d]: %(levelname)s:'
 
177
                            ' %(message)s'))
194
178
    logger.addHandler(syslogger)
195
179
 
196
180
    if debug:
197
181
        console = logging.StreamHandler()
198
 
        console.setFormatter(logging.Formatter("%(asctime)s %(name)s"
199
 
                                               " [%(process)d]:"
200
 
                                               " %(levelname)s:"
201
 
                                               " %(message)s"))
 
182
        console.setFormatter(logging.Formatter('%(asctime)s %(name)s'
 
183
                                               ' [%(process)d]:'
 
184
                                               ' %(levelname)s:'
 
185
                                               ' %(message)s'))
202
186
        logger.addHandler(console)
203
187
    logger.setLevel(level)
204
188
 
224
208
        except OSError as e:
225
209
            if e.errno != errno.ENOENT:
226
210
                raise
227
 
        self.gnupgargs = ["--batch",
228
 
                          "--homedir", self.tempdir,
229
 
                          "--force-mdc",
230
 
                          "--quiet"]
 
211
        self.gnupgargs = ['--batch',
 
212
                          '--homedir', self.tempdir,
 
213
                          '--force-mdc',
 
214
                          '--quiet']
231
215
        # Only GPG version 1 has the --no-use-agent option.
232
216
        if self.gpg == b"gpg" or self.gpg.endswith(b"/gpg"):
233
217
            self.gnupgargs.append("--no-use-agent")
272
256
                dir=self.tempdir) as passfile:
273
257
            passfile.write(passphrase)
274
258
            passfile.flush()
275
 
            proc = subprocess.Popen([self.gpg, "--symmetric",
276
 
                                     "--passphrase-file",
 
259
            proc = subprocess.Popen([self.gpg, '--symmetric',
 
260
                                     '--passphrase-file',
277
261
                                     passfile.name]
278
262
                                    + self.gnupgargs,
279
263
                                    stdin=subprocess.PIPE,
290
274
                dir=self.tempdir) as passfile:
291
275
            passfile.write(passphrase)
292
276
            passfile.flush()
293
 
            proc = subprocess.Popen([self.gpg, "--decrypt",
294
 
                                     "--passphrase-file",
 
277
            proc = subprocess.Popen([self.gpg, '--decrypt',
 
278
                                     '--passphrase-file',
295
279
                                     passfile.name]
296
280
                                    + self.gnupgargs,
297
281
                                    stdin=subprocess.PIPE,
350
334
    Attributes:
351
335
    interface: integer; avahi.IF_UNSPEC or an interface index.
352
336
               Used to optionally bind to the specified interface.
353
 
    name: string; Example: "Mandos"
354
 
    type: string; Example: "_mandos._tcp".
 
337
    name: string; Example: 'Mandos'
 
338
    type: string; Example: '_mandos._tcp'.
355
339
     See <https://www.iana.org/assignments/service-names-port-numbers>
356
340
    port: integer; what port to announce
357
341
    TXT: list of strings; TXT record for the service
435
419
                avahi.DBUS_INTERFACE_ENTRY_GROUP)
436
420
        self.entry_group_state_changed_match = (
437
421
            self.group.connect_to_signal(
438
 
                "StateChanged", self.entry_group_state_changed))
 
422
                'StateChanged', self.entry_group_state_changed))
439
423
        logger.debug("Adding Zeroconf service '%s' of type '%s' ...",
440
424
                     self.name, self.type)
441
425
        self.group.AddService(
524
508
class AvahiServiceToSyslog(AvahiService):
525
509
    def rename(self, *args, **kwargs):
526
510
        """Add the new name to the syslog messages"""
527
 
        ret = super(AvahiServiceToSyslog, self).rename(*args,
528
 
                                                       **kwargs)
 
511
        ret = super(AvahiServiceToSyslog, self).rename(*args, **kwargs)
529
512
        syslogger.setFormatter(logging.Formatter(
530
 
            "Mandos ({}) [%(process)d]: %(levelname)s: %(message)s"
 
513
            'Mandos ({}) [%(process)d]: %(levelname)s: %(message)s'
531
514
            .format(self.name)))
532
515
        return ret
533
516
 
563
546
    OPENPGP_FMT_RAW = 0         # gnutls/openpgp.h
564
547
 
565
548
    # Types
566
 
    class _session_int(ctypes.Structure):
 
549
    class session_int(ctypes.Structure):
567
550
        _fields_ = []
568
 
    session_t = ctypes.POINTER(_session_int)
 
551
    session_t = ctypes.POINTER(session_int)
569
552
 
570
553
    class certificate_credentials_st(ctypes.Structure):
571
554
        _fields_ = []
574
557
    certificate_type_t = ctypes.c_int
575
558
 
576
559
    class datum_t(ctypes.Structure):
577
 
        _fields_ = [("data", ctypes.POINTER(ctypes.c_ubyte)),
578
 
                    ("size", ctypes.c_uint)]
 
560
        _fields_ = [('data', ctypes.POINTER(ctypes.c_ubyte)),
 
561
                    ('size', ctypes.c_uint)]
579
562
 
580
 
    class _openpgp_crt_int(ctypes.Structure):
 
563
    class openpgp_crt_int(ctypes.Structure):
581
564
        _fields_ = []
582
 
    openpgp_crt_t = ctypes.POINTER(_openpgp_crt_int)
 
565
    openpgp_crt_t = ctypes.POINTER(openpgp_crt_int)
583
566
    openpgp_crt_fmt_t = ctypes.c_int  # gnutls/openpgp.h
584
567
    log_func = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p)
585
568
    credentials_type_t = ctypes.c_int
594
577
            # gnutls.strerror()
595
578
            self.code = code
596
579
            if message is None and code is not None:
597
 
                message = gnutls.strerror(code).decode(
598
 
                    "utf-8", errors="replace")
 
580
                message = gnutls.strerror(code)
599
581
            return super(gnutls.Error, self).__init__(
600
582
                message, *args)
601
583
 
602
584
    class CertificateSecurityError(Error):
603
585
        pass
604
586
 
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
587
    # Classes
631
 
    class Credentials(With_from_param):
 
588
    class Credentials:
632
589
        def __init__(self):
633
 
            self._as_parameter_ = gnutls.certificate_credentials_t()
634
 
            gnutls.certificate_allocate_credentials(self)
 
590
            self._c_object = gnutls.certificate_credentials_t()
 
591
            gnutls.certificate_allocate_credentials(
 
592
                ctypes.byref(self._c_object))
635
593
            self.type = gnutls.CRD_CERTIFICATE
636
594
 
637
595
        def __del__(self):
638
 
            gnutls.certificate_free_credentials(self)
 
596
            gnutls.certificate_free_credentials(self._c_object)
639
597
 
640
 
    class ClientSession(With_from_param):
 
598
    class ClientSession:
641
599
        def __init__(self, socket, credentials=None):
642
 
            self._as_parameter_ = gnutls.session_t()
 
600
            self._c_object = gnutls.session_t()
643
601
            gnutls_flags = gnutls.CLIENT
644
602
            if gnutls.check_version(b"3.5.6"):
645
603
                gnutls_flags |= gnutls.NO_TICKETS
646
604
            if gnutls.has_rawpk:
647
605
                gnutls_flags |= gnutls.ENABLE_RAWPK
648
 
            gnutls.init(self, gnutls_flags)
 
606
            gnutls.init(ctypes.byref(self._c_object), gnutls_flags)
649
607
            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)
 
608
            gnutls.set_default_priority(self._c_object)
 
609
            gnutls.transport_set_ptr(self._c_object, socket.fileno())
 
610
            gnutls.handshake_set_private_extensions(self._c_object,
 
611
                                                    True)
653
612
            self.socket = socket
654
613
            if credentials is None:
655
614
                credentials = gnutls.Credentials()
656
 
            gnutls.credentials_set(self, credentials.type,
657
 
                                   credentials)
 
615
            gnutls.credentials_set(self._c_object, credentials.type,
 
616
                                   ctypes.cast(credentials._c_object,
 
617
                                               ctypes.c_void_p))
658
618
            self.credentials = credentials
659
619
 
660
620
        def __del__(self):
661
 
            gnutls.deinit(self)
 
621
            gnutls.deinit(self._c_object)
662
622
 
663
623
        def handshake(self):
664
 
            return gnutls.handshake(self)
 
624
            return gnutls.handshake(self._c_object)
665
625
 
666
626
        def send(self, data):
667
627
            data = bytes(data)
668
628
            data_len = len(data)
669
629
            while data_len > 0:
670
 
                data_len -= gnutls.record_send(self, data[-data_len:],
 
630
                data_len -= gnutls.record_send(self._c_object,
 
631
                                               data[-data_len:],
671
632
                                               data_len)
672
633
 
673
634
        def bye(self):
674
 
            return gnutls.bye(self, gnutls.SHUT_RDWR)
 
635
            return gnutls.bye(self._c_object, gnutls.SHUT_RDWR)
675
636
 
676
637
    # Error handling functions
677
638
    def _error_code(result):
678
639
        """A function to raise exceptions on errors, suitable
679
 
        for the "restype" attribute on ctypes functions"""
680
 
        if result >= gnutls.E_SUCCESS:
 
640
        for the 'restype' attribute on ctypes functions"""
 
641
        if result >= 0:
681
642
            return result
682
643
        if result == gnutls.E_NO_CERTIFICATE_FOUND:
683
644
            raise gnutls.CertificateSecurityError(code=result)
684
645
        raise gnutls.Error(code=result)
685
646
 
686
 
    def _retry_on_error(result, func, arguments,
687
 
                        _error_code=_error_code):
 
647
    def _retry_on_error(result, func, arguments):
688
648
        """A function to retry on some errors, suitable
689
 
        for the "errcheck" attribute on ctypes functions"""
690
 
        while result < gnutls.E_SUCCESS:
 
649
        for the 'errcheck' attribute on ctypes functions"""
 
650
        while result < 0:
691
651
            if result not in (gnutls.E_INTERRUPTED, gnutls.E_AGAIN):
692
652
                return _error_code(result)
693
653
            result = func(*arguments)
698
658
 
699
659
    # Functions
700
660
    priority_set_direct = _library.gnutls_priority_set_direct
701
 
    priority_set_direct.argtypes = [ClientSession, ctypes.c_char_p,
 
661
    priority_set_direct.argtypes = [session_t, ctypes.c_char_p,
702
662
                                    ctypes.POINTER(ctypes.c_char_p)]
703
663
    priority_set_direct.restype = _error_code
704
664
 
705
665
    init = _library.gnutls_init
706
 
    init.argtypes = [PointerTo(ClientSession), ctypes.c_int]
 
666
    init.argtypes = [ctypes.POINTER(session_t), ctypes.c_int]
707
667
    init.restype = _error_code
708
668
 
709
669
    set_default_priority = _library.gnutls_set_default_priority
710
 
    set_default_priority.argtypes = [ClientSession]
 
670
    set_default_priority.argtypes = [session_t]
711
671
    set_default_priority.restype = _error_code
712
672
 
713
673
    record_send = _library.gnutls_record_send
714
 
    record_send.argtypes = [ClientSession, ctypes.c_void_p,
 
674
    record_send.argtypes = [session_t, ctypes.c_void_p,
715
675
                            ctypes.c_size_t]
716
676
    record_send.restype = ctypes.c_ssize_t
717
677
    record_send.errcheck = _retry_on_error
719
679
    certificate_allocate_credentials = (
720
680
        _library.gnutls_certificate_allocate_credentials)
721
681
    certificate_allocate_credentials.argtypes = [
722
 
        PointerTo(Credentials)]
 
682
        ctypes.POINTER(certificate_credentials_t)]
723
683
    certificate_allocate_credentials.restype = _error_code
724
684
 
725
685
    certificate_free_credentials = (
726
686
        _library.gnutls_certificate_free_credentials)
727
 
    certificate_free_credentials.argtypes = [Credentials]
 
687
    certificate_free_credentials.argtypes = [
 
688
        certificate_credentials_t]
728
689
    certificate_free_credentials.restype = None
729
690
 
730
691
    handshake_set_private_extensions = (
731
692
        _library.gnutls_handshake_set_private_extensions)
732
 
    handshake_set_private_extensions.argtypes = [ClientSession,
 
693
    handshake_set_private_extensions.argtypes = [session_t,
733
694
                                                 ctypes.c_int]
734
695
    handshake_set_private_extensions.restype = None
735
696
 
736
697
    credentials_set = _library.gnutls_credentials_set
737
 
    credentials_set.argtypes = [ClientSession, credentials_type_t,
738
 
                                CastToVoidPointer(Credentials)]
 
698
    credentials_set.argtypes = [session_t, credentials_type_t,
 
699
                                ctypes.c_void_p]
739
700
    credentials_set.restype = _error_code
740
701
 
741
702
    strerror = _library.gnutls_strerror
743
704
    strerror.restype = ctypes.c_char_p
744
705
 
745
706
    certificate_type_get = _library.gnutls_certificate_type_get
746
 
    certificate_type_get.argtypes = [ClientSession]
 
707
    certificate_type_get.argtypes = [session_t]
747
708
    certificate_type_get.restype = _error_code
748
709
 
749
710
    certificate_get_peers = _library.gnutls_certificate_get_peers
750
 
    certificate_get_peers.argtypes = [ClientSession,
 
711
    certificate_get_peers.argtypes = [session_t,
751
712
                                      ctypes.POINTER(ctypes.c_uint)]
752
713
    certificate_get_peers.restype = ctypes.POINTER(datum_t)
753
714
 
760
721
    global_set_log_function.restype = None
761
722
 
762
723
    deinit = _library.gnutls_deinit
763
 
    deinit.argtypes = [ClientSession]
 
724
    deinit.argtypes = [session_t]
764
725
    deinit.restype = None
765
726
 
766
727
    handshake = _library.gnutls_handshake
767
 
    handshake.argtypes = [ClientSession]
768
 
    handshake.restype = ctypes.c_int
 
728
    handshake.argtypes = [session_t]
 
729
    handshake.restype = _error_code
769
730
    handshake.errcheck = _retry_on_error
770
731
 
771
732
    transport_set_ptr = _library.gnutls_transport_set_ptr
772
 
    transport_set_ptr.argtypes = [ClientSession, transport_ptr_t]
 
733
    transport_set_ptr.argtypes = [session_t, transport_ptr_t]
773
734
    transport_set_ptr.restype = None
774
735
 
775
736
    bye = _library.gnutls_bye
776
 
    bye.argtypes = [ClientSession, close_request_t]
777
 
    bye.restype = ctypes.c_int
 
737
    bye.argtypes = [session_t, close_request_t]
 
738
    bye.restype = _error_code
778
739
    bye.errcheck = _retry_on_error
779
740
 
780
741
    check_version = _library.gnutls_check_version
797
758
 
798
759
        x509_crt_fmt_t = ctypes.c_int
799
760
 
800
 
        # All the function declarations below are from
801
 
        # gnutls/abstract.h
 
761
        # All the function declarations below are from gnutls/abstract.h
802
762
        pubkey_init = _library.gnutls_pubkey_init
803
763
        pubkey_init.argtypes = [ctypes.POINTER(pubkey_t)]
804
764
        pubkey_init.restype = _error_code
818
778
        pubkey_deinit.argtypes = [pubkey_t]
819
779
        pubkey_deinit.restype = None
820
780
    else:
821
 
        # All the function declarations below are from
822
 
        # gnutls/openpgp.h
 
781
        # All the function declarations below are from gnutls/openpgp.h
823
782
 
824
783
        openpgp_crt_init = _library.gnutls_openpgp_crt_init
825
784
        openpgp_crt_init.argtypes = [ctypes.POINTER(openpgp_crt_t)]
831
790
                                       openpgp_crt_fmt_t]
832
791
        openpgp_crt_import.restype = _error_code
833
792
 
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
 
        ]
 
793
        openpgp_crt_verify_self = _library.gnutls_openpgp_crt_verify_self
 
794
        openpgp_crt_verify_self.argtypes = [openpgp_crt_t, ctypes.c_uint,
 
795
                                            ctypes.POINTER(ctypes.c_uint)]
841
796
        openpgp_crt_verify_self.restype = _error_code
842
797
 
843
798
        openpgp_crt_deinit = _library.gnutls_openpgp_crt_deinit
854
809
 
855
810
    if check_version(b"3.6.4"):
856
811
        certificate_type_get2 = _library.gnutls_certificate_type_get2
857
 
        certificate_type_get2.argtypes = [ClientSession, ctypes.c_int]
 
812
        certificate_type_get2.argtypes = [session_t, ctypes.c_int]
858
813
        certificate_type_get2.restype = _error_code
859
814
 
860
815
    # Remove non-public functions
876
831
    """A representation of a client host served by this server.
877
832
 
878
833
    Attributes:
879
 
    approved:   bool(); None if not yet approved/disapproved
 
834
    approved:   bool(); 'None' if not yet approved/disapproved
880
835
    approval_delay: datetime.timedelta(); Time to wait for approval
881
836
    approval_duration: datetime.timedelta(); Duration of one approval
882
837
    checker: multiprocessing.Process(); a running checker process used
883
 
             to see if the client lives. None if no process is
 
838
             to see if the client lives. 'None' if no process is
884
839
             running.
885
840
    checker_callback_tag: a GLib event source tag, or None
886
841
    checker_command: string; External command which is run to check
1163
1118
        if self.checker is None:
1164
1119
            # Escape attributes for the shell
1165
1120
            escaped_attrs = {
1166
 
                attr: shlex.quote(str(getattr(self, attr)))
 
1121
                attr: re.escape(str(getattr(self, attr)))
1167
1122
                for attr in self.runtime_expansions}
1168
1123
            try:
1169
1124
                command = self.checker_command % escaped_attrs
1242
1197
        func._dbus_name = func.__name__
1243
1198
        if func._dbus_name.endswith("_dbus_property"):
1244
1199
            func._dbus_name = func._dbus_name[:-14]
1245
 
        func._dbus_get_args_options = {"byte_arrays": byte_arrays}
 
1200
        func._dbus_get_args_options = {'byte_arrays': byte_arrays}
1246
1201
        return func
1247
1202
 
1248
1203
    return decorator
1337
1292
 
1338
1293
    @dbus.service.method(dbus.INTROSPECTABLE_IFACE,
1339
1294
                         out_signature="s",
1340
 
                         path_keyword="object_path",
1341
 
                         connection_keyword="connection")
 
1295
                         path_keyword='object_path',
 
1296
                         connection_keyword='connection')
1342
1297
    def Introspect(self, object_path, connection):
1343
1298
        """Overloading of standard D-Bus method.
1344
1299
 
1497
1452
 
1498
1453
    @dbus.service.method(dbus.INTROSPECTABLE_IFACE,
1499
1454
                         out_signature="s",
1500
 
                         path_keyword="object_path",
1501
 
                         connection_keyword="connection")
 
1455
                         path_keyword='object_path',
 
1456
                         connection_keyword='connection')
1502
1457
    def Introspect(self, object_path, connection):
1503
1458
        """Overloading of standard D-Bus method.
1504
1459
 
1599
1554
 
1600
1555
    @dbus.service.method(dbus.INTROSPECTABLE_IFACE,
1601
1556
                         out_signature="s",
1602
 
                         path_keyword="object_path",
1603
 
                         connection_keyword="connection")
 
1557
                         path_keyword='object_path',
 
1558
                         connection_keyword='connection')
1604
1559
    def Introspect(self, object_path, connection):
1605
1560
        """Overloading of standard D-Bus method.
1606
1561
 
2272
2227
class ProxyClient:
2273
2228
    def __init__(self, child_pipe, key_id, fpr, address):
2274
2229
        self._pipe = child_pipe
2275
 
        self._pipe.send(("init", key_id, fpr, address))
 
2230
        self._pipe.send(('init', key_id, fpr, address))
2276
2231
        if not self._pipe.recv():
2277
2232
            raise KeyError(key_id or fpr)
2278
2233
 
2279
2234
    def __getattribute__(self, name):
2280
 
        if name == "_pipe":
 
2235
        if name == '_pipe':
2281
2236
            return super(ProxyClient, self).__getattribute__(name)
2282
 
        self._pipe.send(("getattr", name))
 
2237
        self._pipe.send(('getattr', name))
2283
2238
        data = self._pipe.recv()
2284
 
        if data[0] == "data":
 
2239
        if data[0] == 'data':
2285
2240
            return data[1]
2286
 
        if data[0] == "function":
 
2241
        if data[0] == 'function':
2287
2242
 
2288
2243
            def func(*args, **kwargs):
2289
 
                self._pipe.send(("funcall", name, args, kwargs))
 
2244
                self._pipe.send(('funcall', name, args, kwargs))
2290
2245
                return self._pipe.recv()[1]
2291
2246
 
2292
2247
            return func
2293
2248
 
2294
2249
    def __setattr__(self, name, value):
2295
 
        if name == "_pipe":
 
2250
        if name == '_pipe':
2296
2251
            return super(ProxyClient, self).__setattr__(name, value)
2297
 
        self._pipe.send(("setattr", name, value))
 
2252
        self._pipe.send(('setattr', name, value))
2298
2253
 
2299
2254
 
2300
2255
class ClientHandler(socketserver.BaseRequestHandler, object):
2312
2267
 
2313
2268
            session = gnutls.ClientSession(self.request)
2314
2269
 
2315
 
            # priority = ":".join(("NONE", "+VERS-TLS1.1",
 
2270
            # priority = ':'.join(("NONE", "+VERS-TLS1.1",
2316
2271
            #                       "+AES-256-CBC", "+SHA1",
2317
2272
            #                       "+COMP-NULL", "+CTYPE-OPENPGP",
2318
2273
            #                       "+DHE-DSS"))
2320
2275
            priority = self.server.gnutls_priority
2321
2276
            if priority is None:
2322
2277
                priority = "NORMAL"
2323
 
            gnutls.priority_set_direct(session,
2324
 
                                       priority.encode("utf-8"), None)
 
2278
            gnutls.priority_set_direct(session._c_object,
 
2279
                                       priority.encode("utf-8"),
 
2280
                                       None)
2325
2281
 
2326
2282
            # Start communication using the Mandos protocol
2327
2283
            # Get protocol number
2354
2310
                    except (TypeError, gnutls.Error) as error:
2355
2311
                        logger.warning("Bad certificate: %s", error)
2356
2312
                        return
2357
 
                    logger.debug("Key ID: %s",
2358
 
                                 key_id.decode("utf-8",
2359
 
                                               errors="replace"))
 
2313
                    logger.debug("Key ID: %s", key_id)
2360
2314
 
2361
2315
                else:
2362
2316
                    key_id = b""
2454
2408
    def peer_certificate(session):
2455
2409
        "Return the peer's certificate as a bytestring"
2456
2410
        try:
2457
 
            cert_type = gnutls.certificate_type_get2(
2458
 
                session, gnutls.CTYPE_PEERS)
 
2411
            cert_type = gnutls.certificate_type_get2(session._c_object,
 
2412
                                                     gnutls.CTYPE_PEERS)
2459
2413
        except AttributeError:
2460
 
            cert_type = gnutls.certificate_type_get(session)
 
2414
            cert_type = gnutls.certificate_type_get(session._c_object)
2461
2415
        if gnutls.has_rawpk:
2462
2416
            valid_cert_types = frozenset((gnutls.CRT_RAWPK,))
2463
2417
        else:
2470
2424
            return b""
2471
2425
        list_size = ctypes.c_uint(1)
2472
2426
        cert_list = (gnutls.certificate_get_peers
2473
 
                     (session, ctypes.byref(list_size)))
 
2427
                     (session._c_object, ctypes.byref(list_size)))
2474
2428
        if not bool(cert_list) and list_size.value != 0:
2475
2429
            raise gnutls.Error("error getting peer certificate")
2476
2430
        if list_size.value == 0:
2498
2452
        buf = ctypes.create_string_buffer(32)
2499
2453
        buf_len = ctypes.c_size_t(len(buf))
2500
2454
        # 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))
 
2455
        gnutls.pubkey_get_key_id(pubkey,
 
2456
                                 gnutls.KEYID_USE_SHA256,
 
2457
                                 ctypes.cast(ctypes.byref(buf),
 
2458
                                             ctypes.POINTER(ctypes.c_ubyte)),
 
2459
                                 ctypes.byref(buf_len))
2507
2460
        # Deinit the certificate
2508
2461
        gnutls.pubkey_deinit(pubkey)
2509
2462
 
2590
2543
 
2591
2544
class IPv6_TCPServer(MultiprocessingMixInWithPipe,
2592
2545
                     socketserver.TCPServer):
2593
 
    """IPv6-capable TCP server.  Accepts None as address and/or port
 
2546
    """IPv6-capable TCP server.  Accepts 'None' as address and/or port
2594
2547
 
2595
2548
    Attributes:
2596
2549
        enabled:        Boolean; whether this server is activated yet
2748
2701
        request = parent_pipe.recv()
2749
2702
        command = request[0]
2750
2703
 
2751
 
        if command == "init":
 
2704
        if command == 'init':
2752
2705
            key_id = request[1].decode("ascii")
2753
2706
            fpr = request[2].decode("ascii")
2754
2707
            address = request[3]
2755
2708
 
2756
2709
            for c in self.clients.values():
2757
 
                if key_id == ("E3B0C44298FC1C149AFBF4C8996FB924"
2758
 
                              "27AE41E4649B934CA495991B7852B855"):
 
2710
                if key_id == "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855":
2759
2711
                    continue
2760
2712
                if key_id and c.key_id == key_id:
2761
2713
                    client = c
2784
2736
            # remove the old hook in favor of the new above hook on
2785
2737
            # same fileno
2786
2738
            return False
2787
 
        if command == "funcall":
 
2739
        if command == 'funcall':
2788
2740
            funcname = request[1]
2789
2741
            args = request[2]
2790
2742
            kwargs = request[3]
2791
2743
 
2792
 
            parent_pipe.send(("data", getattr(client_object,
 
2744
            parent_pipe.send(('data', getattr(client_object,
2793
2745
                                              funcname)(*args,
2794
2746
                                                        **kwargs)))
2795
2747
 
2796
 
        if command == "getattr":
 
2748
        if command == 'getattr':
2797
2749
            attrname = request[1]
2798
2750
            if isinstance(client_object.__getattribute__(attrname),
2799
 
                          collections.abc.Callable):
2800
 
                parent_pipe.send(("function", ))
 
2751
                          collections.Callable):
 
2752
                parent_pipe.send(('function', ))
2801
2753
            else:
2802
2754
                parent_pipe.send((
2803
 
                    "data", client_object.__getattribute__(attrname)))
 
2755
                    'data', client_object.__getattribute__(attrname)))
2804
2756
 
2805
 
        if command == "setattr":
 
2757
        if command == 'setattr':
2806
2758
            attrname = request[1]
2807
2759
            value = request[2]
2808
2760
            setattr(client_object, attrname, value)
2813
2765
def rfc3339_duration_to_delta(duration):
2814
2766
    """Parse an RFC 3339 "duration" and return a datetime.timedelta
2815
2767
 
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
 
2768
    >>> rfc3339_duration_to_delta("P7D") == datetime.timedelta(7)
 
2769
    True
 
2770
    >>> rfc3339_duration_to_delta("PT60S") == datetime.timedelta(0, 60)
 
2771
    True
 
2772
    >>> rfc3339_duration_to_delta("PT60M") == datetime.timedelta(0, 3600)
 
2773
    True
 
2774
    >>> rfc3339_duration_to_delta("PT24H") == datetime.timedelta(1)
 
2775
    True
 
2776
    >>> rfc3339_duration_to_delta("P1W") == datetime.timedelta(7)
 
2777
    True
 
2778
    >>> rfc3339_duration_to_delta("PT5M30S") == datetime.timedelta(0, 330)
 
2779
    True
 
2780
    >>> rfc3339_duration_to_delta("P1DT3M20S") == datetime.timedelta(1, 200)
 
2781
    True
2832
2782
    """
2833
2783
 
2834
2784
    # Parsing an RFC 3339 duration with regular expressions is not
2914
2864
def string_to_delta(interval):
2915
2865
    """Parse a string and return a datetime.timedelta
2916
2866
 
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)
 
2867
    >>> string_to_delta('7d') == datetime.timedelta(7)
 
2868
    True
 
2869
    >>> string_to_delta('60s') == datetime.timedelta(0, 60)
 
2870
    True
 
2871
    >>> string_to_delta('60m') == datetime.timedelta(0, 3600)
 
2872
    True
 
2873
    >>> string_to_delta('24h') == datetime.timedelta(1)
 
2874
    True
 
2875
    >>> string_to_delta('1w') == datetime.timedelta(7)
 
2876
    True
 
2877
    >>> string_to_delta('5m 30s') == datetime.timedelta(0, 330)
2928
2878
    True
2929
2879
    """
2930
2880
 
3134
3084
 
3135
3085
    if server_settings["servicename"] != "Mandos":
3136
3086
        syslogger.setFormatter(
3137
 
            logging.Formatter("Mandos ({}) [%(process)d]:"
3138
 
                              " %(levelname)s: %(message)s".format(
 
3087
            logging.Formatter('Mandos ({}) [%(process)d]:'
 
3088
                              ' %(levelname)s: %(message)s'.format(
3139
3089
                                  server_settings["servicename"])))
3140
3090
 
3141
3091
    # Parse config file with clients
3201
3151
 
3202
3152
        @gnutls.log_func
3203
3153
        def debug_gnutls(level, string):
3204
 
            logger.debug("GnuTLS: %s",
3205
 
                         string[:-1].decode("utf-8",
3206
 
                                            errors="replace"))
 
3154
            logger.debug("GnuTLS: %s", string[:-1])
3207
3155
 
3208
3156
        gnutls.global_set_log_function(debug_gnutls)
3209
3157
 
3584
3532
 
3585
3533
        try:
3586
3534
            with tempfile.NamedTemporaryFile(
3587
 
                    mode="wb",
 
3535
                    mode='wb',
3588
3536
                    suffix=".pickle",
3589
 
                    prefix="clients-",
 
3537
                    prefix='clients-',
3590
3538
                    dir=os.path.dirname(stored_state_path),
3591
3539
                    delete=False) as stored_state:
3592
3540
                pickle.dump((clients, client_settings), stored_state,
3679
3627
 
3680
3628
def should_only_run_tests():
3681
3629
    parser = argparse.ArgumentParser(add_help=False)
3682
 
    parser.add_argument("--check", action="store_true")
 
3630
    parser.add_argument("--check", action='store_true')
3683
3631
    args, unknown_args = parser.parse_known_args()
3684
3632
    run_tests = args.check
3685
3633
    if run_tests:
3693
3641
    tests.addTests(doctest.DocTestSuite())
3694
3642
    return tests
3695
3643
 
3696
 
if __name__ == "__main__":
 
3644
if __name__ == '__main__':
3697
3645
    try:
3698
3646
        if should_only_run_tests():
3699
3647
            # Call using ./mandos --check [--verbose]