/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 Hogeborn
  • Date: 2021-03-21 18:48:43 UTC
  • Revision ID: teddy@recompile.se-20210321184843-va7cywxnlf31tbyt
Break long line (white space change only)

* plugin-runner.c (main): Break long line.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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(
527
527
        ret = super(AvahiServiceToSyslog, self).rename(*args,
528
528
                                                       **kwargs)
529
529
        syslogger.setFormatter(logging.Formatter(
530
 
            "Mandos ({}) [%(process)d]: %(levelname)s: %(message)s"
 
530
            'Mandos ({}) [%(process)d]: %(levelname)s: %(message)s'
531
531
            .format(self.name)))
532
532
        return ret
533
533
 
563
563
    OPENPGP_FMT_RAW = 0         # gnutls/openpgp.h
564
564
 
565
565
    # Types
566
 
    class _session_int(ctypes.Structure):
 
566
    class session_int(ctypes.Structure):
567
567
        _fields_ = []
568
 
    session_t = ctypes.POINTER(_session_int)
 
568
    session_t = ctypes.POINTER(session_int)
569
569
 
570
570
    class certificate_credentials_st(ctypes.Structure):
571
571
        _fields_ = []
574
574
    certificate_type_t = ctypes.c_int
575
575
 
576
576
    class datum_t(ctypes.Structure):
577
 
        _fields_ = [("data", ctypes.POINTER(ctypes.c_ubyte)),
578
 
                    ("size", ctypes.c_uint)]
 
577
        _fields_ = [('data', ctypes.POINTER(ctypes.c_ubyte)),
 
578
                    ('size', ctypes.c_uint)]
579
579
 
580
 
    class _openpgp_crt_int(ctypes.Structure):
 
580
    class openpgp_crt_int(ctypes.Structure):
581
581
        _fields_ = []
582
 
    openpgp_crt_t = ctypes.POINTER(_openpgp_crt_int)
 
582
    openpgp_crt_t = ctypes.POINTER(openpgp_crt_int)
583
583
    openpgp_crt_fmt_t = ctypes.c_int  # gnutls/openpgp.h
584
584
    log_func = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p)
585
585
    credentials_type_t = ctypes.c_int
594
594
            # gnutls.strerror()
595
595
            self.code = code
596
596
            if message is None and code is not None:
597
 
                message = gnutls.strerror(code).decode(
598
 
                    "utf-8", errors="replace")
 
597
                message = gnutls.strerror(code)
599
598
            return super(gnutls.Error, self).__init__(
600
599
                message, *args)
601
600
 
602
601
    class CertificateSecurityError(Error):
603
602
        pass
604
603
 
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
604
    # Classes
631
 
    class Credentials(With_from_param):
 
605
    class Credentials:
632
606
        def __init__(self):
633
 
            self._as_parameter_ = gnutls.certificate_credentials_t()
634
 
            gnutls.certificate_allocate_credentials(self)
 
607
            self._c_object = gnutls.certificate_credentials_t()
 
608
            gnutls.certificate_allocate_credentials(
 
609
                ctypes.byref(self._c_object))
635
610
            self.type = gnutls.CRD_CERTIFICATE
636
611
 
637
612
        def __del__(self):
638
 
            gnutls.certificate_free_credentials(self)
 
613
            gnutls.certificate_free_credentials(self._c_object)
639
614
 
640
 
    class ClientSession(With_from_param):
 
615
    class ClientSession:
641
616
        def __init__(self, socket, credentials=None):
642
 
            self._as_parameter_ = gnutls.session_t()
 
617
            self._c_object = gnutls.session_t()
643
618
            gnutls_flags = gnutls.CLIENT
644
619
            if gnutls.check_version(b"3.5.6"):
645
620
                gnutls_flags |= gnutls.NO_TICKETS
646
621
            if gnutls.has_rawpk:
647
622
                gnutls_flags |= gnutls.ENABLE_RAWPK
648
 
            gnutls.init(self, gnutls_flags)
 
623
            gnutls.init(ctypes.byref(self._c_object), gnutls_flags)
649
624
            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)
 
625
            gnutls.set_default_priority(self._c_object)
 
626
            gnutls.transport_set_ptr(self._c_object, socket.fileno())
 
627
            gnutls.handshake_set_private_extensions(self._c_object,
 
628
                                                    True)
653
629
            self.socket = socket
654
630
            if credentials is None:
655
631
                credentials = gnutls.Credentials()
656
 
            gnutls.credentials_set(self, credentials.type,
657
 
                                   credentials)
 
632
            gnutls.credentials_set(self._c_object, credentials.type,
 
633
                                   ctypes.cast(credentials._c_object,
 
634
                                               ctypes.c_void_p))
658
635
            self.credentials = credentials
659
636
 
660
637
        def __del__(self):
661
 
            gnutls.deinit(self)
 
638
            gnutls.deinit(self._c_object)
662
639
 
663
640
        def handshake(self):
664
 
            return gnutls.handshake(self)
 
641
            return gnutls.handshake(self._c_object)
665
642
 
666
643
        def send(self, data):
667
644
            data = bytes(data)
668
645
            data_len = len(data)
669
646
            while data_len > 0:
670
 
                data_len -= gnutls.record_send(self, data[-data_len:],
 
647
                data_len -= gnutls.record_send(self._c_object,
 
648
                                               data[-data_len:],
671
649
                                               data_len)
672
650
 
673
651
        def bye(self):
674
 
            return gnutls.bye(self, gnutls.SHUT_RDWR)
 
652
            return gnutls.bye(self._c_object, gnutls.SHUT_RDWR)
675
653
 
676
654
    # Error handling functions
677
655
    def _error_code(result):
678
656
        """A function to raise exceptions on errors, suitable
679
 
        for the "restype" attribute on ctypes functions"""
680
 
        if result >= gnutls.E_SUCCESS:
 
657
        for the 'restype' attribute on ctypes functions"""
 
658
        if result >= 0:
681
659
            return result
682
660
        if result == gnutls.E_NO_CERTIFICATE_FOUND:
683
661
            raise gnutls.CertificateSecurityError(code=result)
684
662
        raise gnutls.Error(code=result)
685
663
 
686
 
    def _retry_on_error(result, func, arguments,
687
 
                        _error_code=_error_code):
 
664
    def _retry_on_error(result, func, arguments):
688
665
        """A function to retry on some errors, suitable
689
 
        for the "errcheck" attribute on ctypes functions"""
690
 
        while result < gnutls.E_SUCCESS:
 
666
        for the 'errcheck' attribute on ctypes functions"""
 
667
        while result < 0:
691
668
            if result not in (gnutls.E_INTERRUPTED, gnutls.E_AGAIN):
692
669
                return _error_code(result)
693
670
            result = func(*arguments)
698
675
 
699
676
    # Functions
700
677
    priority_set_direct = _library.gnutls_priority_set_direct
701
 
    priority_set_direct.argtypes = [ClientSession, ctypes.c_char_p,
 
678
    priority_set_direct.argtypes = [session_t, ctypes.c_char_p,
702
679
                                    ctypes.POINTER(ctypes.c_char_p)]
703
680
    priority_set_direct.restype = _error_code
704
681
 
705
682
    init = _library.gnutls_init
706
 
    init.argtypes = [PointerTo(ClientSession), ctypes.c_int]
 
683
    init.argtypes = [ctypes.POINTER(session_t), ctypes.c_int]
707
684
    init.restype = _error_code
708
685
 
709
686
    set_default_priority = _library.gnutls_set_default_priority
710
 
    set_default_priority.argtypes = [ClientSession]
 
687
    set_default_priority.argtypes = [session_t]
711
688
    set_default_priority.restype = _error_code
712
689
 
713
690
    record_send = _library.gnutls_record_send
714
 
    record_send.argtypes = [ClientSession, ctypes.c_void_p,
 
691
    record_send.argtypes = [session_t, ctypes.c_void_p,
715
692
                            ctypes.c_size_t]
716
693
    record_send.restype = ctypes.c_ssize_t
717
694
    record_send.errcheck = _retry_on_error
719
696
    certificate_allocate_credentials = (
720
697
        _library.gnutls_certificate_allocate_credentials)
721
698
    certificate_allocate_credentials.argtypes = [
722
 
        PointerTo(Credentials)]
 
699
        ctypes.POINTER(certificate_credentials_t)]
723
700
    certificate_allocate_credentials.restype = _error_code
724
701
 
725
702
    certificate_free_credentials = (
726
703
        _library.gnutls_certificate_free_credentials)
727
 
    certificate_free_credentials.argtypes = [Credentials]
 
704
    certificate_free_credentials.argtypes = [
 
705
        certificate_credentials_t]
728
706
    certificate_free_credentials.restype = None
729
707
 
730
708
    handshake_set_private_extensions = (
731
709
        _library.gnutls_handshake_set_private_extensions)
732
 
    handshake_set_private_extensions.argtypes = [ClientSession,
 
710
    handshake_set_private_extensions.argtypes = [session_t,
733
711
                                                 ctypes.c_int]
734
712
    handshake_set_private_extensions.restype = None
735
713
 
736
714
    credentials_set = _library.gnutls_credentials_set
737
 
    credentials_set.argtypes = [ClientSession, credentials_type_t,
738
 
                                CastToVoidPointer(Credentials)]
 
715
    credentials_set.argtypes = [session_t, credentials_type_t,
 
716
                                ctypes.c_void_p]
739
717
    credentials_set.restype = _error_code
740
718
 
741
719
    strerror = _library.gnutls_strerror
743
721
    strerror.restype = ctypes.c_char_p
744
722
 
745
723
    certificate_type_get = _library.gnutls_certificate_type_get
746
 
    certificate_type_get.argtypes = [ClientSession]
 
724
    certificate_type_get.argtypes = [session_t]
747
725
    certificate_type_get.restype = _error_code
748
726
 
749
727
    certificate_get_peers = _library.gnutls_certificate_get_peers
750
 
    certificate_get_peers.argtypes = [ClientSession,
 
728
    certificate_get_peers.argtypes = [session_t,
751
729
                                      ctypes.POINTER(ctypes.c_uint)]
752
730
    certificate_get_peers.restype = ctypes.POINTER(datum_t)
753
731
 
760
738
    global_set_log_function.restype = None
761
739
 
762
740
    deinit = _library.gnutls_deinit
763
 
    deinit.argtypes = [ClientSession]
 
741
    deinit.argtypes = [session_t]
764
742
    deinit.restype = None
765
743
 
766
744
    handshake = _library.gnutls_handshake
767
 
    handshake.argtypes = [ClientSession]
768
 
    handshake.restype = ctypes.c_int
 
745
    handshake.argtypes = [session_t]
 
746
    handshake.restype = _error_code
769
747
    handshake.errcheck = _retry_on_error
770
748
 
771
749
    transport_set_ptr = _library.gnutls_transport_set_ptr
772
 
    transport_set_ptr.argtypes = [ClientSession, transport_ptr_t]
 
750
    transport_set_ptr.argtypes = [session_t, transport_ptr_t]
773
751
    transport_set_ptr.restype = None
774
752
 
775
753
    bye = _library.gnutls_bye
776
 
    bye.argtypes = [ClientSession, close_request_t]
777
 
    bye.restype = ctypes.c_int
 
754
    bye.argtypes = [session_t, close_request_t]
 
755
    bye.restype = _error_code
778
756
    bye.errcheck = _retry_on_error
779
757
 
780
758
    check_version = _library.gnutls_check_version
854
832
 
855
833
    if check_version(b"3.6.4"):
856
834
        certificate_type_get2 = _library.gnutls_certificate_type_get2
857
 
        certificate_type_get2.argtypes = [ClientSession, ctypes.c_int]
 
835
        certificate_type_get2.argtypes = [session_t, ctypes.c_int]
858
836
        certificate_type_get2.restype = _error_code
859
837
 
860
838
    # Remove non-public functions
876
854
    """A representation of a client host served by this server.
877
855
 
878
856
    Attributes:
879
 
    approved:   bool(); None if not yet approved/disapproved
 
857
    approved:   bool(); 'None' if not yet approved/disapproved
880
858
    approval_delay: datetime.timedelta(); Time to wait for approval
881
859
    approval_duration: datetime.timedelta(); Duration of one approval
882
860
    checker: multiprocessing.Process(); a running checker process used
883
 
             to see if the client lives. None if no process is
 
861
             to see if the client lives. 'None' if no process is
884
862
             running.
885
863
    checker_callback_tag: a GLib event source tag, or None
886
864
    checker_command: string; External command which is run to check
1242
1220
        func._dbus_name = func.__name__
1243
1221
        if func._dbus_name.endswith("_dbus_property"):
1244
1222
            func._dbus_name = func._dbus_name[:-14]
1245
 
        func._dbus_get_args_options = {"byte_arrays": byte_arrays}
 
1223
        func._dbus_get_args_options = {'byte_arrays': byte_arrays}
1246
1224
        return func
1247
1225
 
1248
1226
    return decorator
1337
1315
 
1338
1316
    @dbus.service.method(dbus.INTROSPECTABLE_IFACE,
1339
1317
                         out_signature="s",
1340
 
                         path_keyword="object_path",
1341
 
                         connection_keyword="connection")
 
1318
                         path_keyword='object_path',
 
1319
                         connection_keyword='connection')
1342
1320
    def Introspect(self, object_path, connection):
1343
1321
        """Overloading of standard D-Bus method.
1344
1322
 
1497
1475
 
1498
1476
    @dbus.service.method(dbus.INTROSPECTABLE_IFACE,
1499
1477
                         out_signature="s",
1500
 
                         path_keyword="object_path",
1501
 
                         connection_keyword="connection")
 
1478
                         path_keyword='object_path',
 
1479
                         connection_keyword='connection')
1502
1480
    def Introspect(self, object_path, connection):
1503
1481
        """Overloading of standard D-Bus method.
1504
1482
 
1599
1577
 
1600
1578
    @dbus.service.method(dbus.INTROSPECTABLE_IFACE,
1601
1579
                         out_signature="s",
1602
 
                         path_keyword="object_path",
1603
 
                         connection_keyword="connection")
 
1580
                         path_keyword='object_path',
 
1581
                         connection_keyword='connection')
1604
1582
    def Introspect(self, object_path, connection):
1605
1583
        """Overloading of standard D-Bus method.
1606
1584
 
2272
2250
class ProxyClient:
2273
2251
    def __init__(self, child_pipe, key_id, fpr, address):
2274
2252
        self._pipe = child_pipe
2275
 
        self._pipe.send(("init", key_id, fpr, address))
 
2253
        self._pipe.send(('init', key_id, fpr, address))
2276
2254
        if not self._pipe.recv():
2277
2255
            raise KeyError(key_id or fpr)
2278
2256
 
2279
2257
    def __getattribute__(self, name):
2280
 
        if name == "_pipe":
 
2258
        if name == '_pipe':
2281
2259
            return super(ProxyClient, self).__getattribute__(name)
2282
 
        self._pipe.send(("getattr", name))
 
2260
        self._pipe.send(('getattr', name))
2283
2261
        data = self._pipe.recv()
2284
 
        if data[0] == "data":
 
2262
        if data[0] == 'data':
2285
2263
            return data[1]
2286
 
        if data[0] == "function":
 
2264
        if data[0] == 'function':
2287
2265
 
2288
2266
            def func(*args, **kwargs):
2289
 
                self._pipe.send(("funcall", name, args, kwargs))
 
2267
                self._pipe.send(('funcall', name, args, kwargs))
2290
2268
                return self._pipe.recv()[1]
2291
2269
 
2292
2270
            return func
2293
2271
 
2294
2272
    def __setattr__(self, name, value):
2295
 
        if name == "_pipe":
 
2273
        if name == '_pipe':
2296
2274
            return super(ProxyClient, self).__setattr__(name, value)
2297
 
        self._pipe.send(("setattr", name, value))
 
2275
        self._pipe.send(('setattr', name, value))
2298
2276
 
2299
2277
 
2300
2278
class ClientHandler(socketserver.BaseRequestHandler, object):
2312
2290
 
2313
2291
            session = gnutls.ClientSession(self.request)
2314
2292
 
2315
 
            # priority = ":".join(("NONE", "+VERS-TLS1.1",
 
2293
            # priority = ':'.join(("NONE", "+VERS-TLS1.1",
2316
2294
            #                       "+AES-256-CBC", "+SHA1",
2317
2295
            #                       "+COMP-NULL", "+CTYPE-OPENPGP",
2318
2296
            #                       "+DHE-DSS"))
2320
2298
            priority = self.server.gnutls_priority
2321
2299
            if priority is None:
2322
2300
                priority = "NORMAL"
2323
 
            gnutls.priority_set_direct(session,
2324
 
                                       priority.encode("utf-8"), None)
 
2301
            gnutls.priority_set_direct(session._c_object,
 
2302
                                       priority.encode("utf-8"),
 
2303
                                       None)
2325
2304
 
2326
2305
            # Start communication using the Mandos protocol
2327
2306
            # Get protocol number
2354
2333
                    except (TypeError, gnutls.Error) as error:
2355
2334
                        logger.warning("Bad certificate: %s", error)
2356
2335
                        return
2357
 
                    logger.debug("Key ID: %s",
2358
 
                                 key_id.decode("utf-8",
2359
 
                                               errors="replace"))
 
2336
                    logger.debug("Key ID: %s", key_id)
2360
2337
 
2361
2338
                else:
2362
2339
                    key_id = b""
2454
2431
    def peer_certificate(session):
2455
2432
        "Return the peer's certificate as a bytestring"
2456
2433
        try:
2457
 
            cert_type = gnutls.certificate_type_get2(
2458
 
                session, gnutls.CTYPE_PEERS)
 
2434
            cert_type = gnutls.certificate_type_get2(session._c_object,
 
2435
                                                     gnutls.CTYPE_PEERS)
2459
2436
        except AttributeError:
2460
 
            cert_type = gnutls.certificate_type_get(session)
 
2437
            cert_type = gnutls.certificate_type_get(session._c_object)
2461
2438
        if gnutls.has_rawpk:
2462
2439
            valid_cert_types = frozenset((gnutls.CRT_RAWPK,))
2463
2440
        else:
2470
2447
            return b""
2471
2448
        list_size = ctypes.c_uint(1)
2472
2449
        cert_list = (gnutls.certificate_get_peers
2473
 
                     (session, ctypes.byref(list_size)))
 
2450
                     (session._c_object, ctypes.byref(list_size)))
2474
2451
        if not bool(cert_list) and list_size.value != 0:
2475
2452
            raise gnutls.Error("error getting peer certificate")
2476
2453
        if list_size.value == 0:
2590
2567
 
2591
2568
class IPv6_TCPServer(MultiprocessingMixInWithPipe,
2592
2569
                     socketserver.TCPServer):
2593
 
    """IPv6-capable TCP server.  Accepts None as address and/or port
 
2570
    """IPv6-capable TCP server.  Accepts 'None' as address and/or port
2594
2571
 
2595
2572
    Attributes:
2596
2573
        enabled:        Boolean; whether this server is activated yet
2748
2725
        request = parent_pipe.recv()
2749
2726
        command = request[0]
2750
2727
 
2751
 
        if command == "init":
 
2728
        if command == 'init':
2752
2729
            key_id = request[1].decode("ascii")
2753
2730
            fpr = request[2].decode("ascii")
2754
2731
            address = request[3]
2784
2761
            # remove the old hook in favor of the new above hook on
2785
2762
            # same fileno
2786
2763
            return False
2787
 
        if command == "funcall":
 
2764
        if command == 'funcall':
2788
2765
            funcname = request[1]
2789
2766
            args = request[2]
2790
2767
            kwargs = request[3]
2791
2768
 
2792
 
            parent_pipe.send(("data", getattr(client_object,
 
2769
            parent_pipe.send(('data', getattr(client_object,
2793
2770
                                              funcname)(*args,
2794
2771
                                                        **kwargs)))
2795
2772
 
2796
 
        if command == "getattr":
 
2773
        if command == 'getattr':
2797
2774
            attrname = request[1]
2798
2775
            if isinstance(client_object.__getattribute__(attrname),
2799
2776
                          collections.abc.Callable):
2800
 
                parent_pipe.send(("function", ))
 
2777
                parent_pipe.send(('function', ))
2801
2778
            else:
2802
2779
                parent_pipe.send((
2803
 
                    "data", client_object.__getattribute__(attrname)))
 
2780
                    'data', client_object.__getattribute__(attrname)))
2804
2781
 
2805
 
        if command == "setattr":
 
2782
        if command == 'setattr':
2806
2783
            attrname = request[1]
2807
2784
            value = request[2]
2808
2785
            setattr(client_object, attrname, value)
2914
2891
def string_to_delta(interval):
2915
2892
    """Parse a string and return a datetime.timedelta
2916
2893
 
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)
 
2894
    >>> string_to_delta('7d') == datetime.timedelta(7)
 
2895
    True
 
2896
    >>> string_to_delta('60s') == datetime.timedelta(0, 60)
 
2897
    True
 
2898
    >>> string_to_delta('60m') == datetime.timedelta(0, 3600)
 
2899
    True
 
2900
    >>> string_to_delta('24h') == datetime.timedelta(1)
 
2901
    True
 
2902
    >>> string_to_delta('1w') == datetime.timedelta(7)
 
2903
    True
 
2904
    >>> string_to_delta('5m 30s') == datetime.timedelta(0, 330)
2928
2905
    True
2929
2906
    """
2930
2907
 
3134
3111
 
3135
3112
    if server_settings["servicename"] != "Mandos":
3136
3113
        syslogger.setFormatter(
3137
 
            logging.Formatter("Mandos ({}) [%(process)d]:"
3138
 
                              " %(levelname)s: %(message)s".format(
 
3114
            logging.Formatter('Mandos ({}) [%(process)d]:'
 
3115
                              ' %(levelname)s: %(message)s'.format(
3139
3116
                                  server_settings["servicename"])))
3140
3117
 
3141
3118
    # Parse config file with clients
3201
3178
 
3202
3179
        @gnutls.log_func
3203
3180
        def debug_gnutls(level, string):
3204
 
            logger.debug("GnuTLS: %s",
3205
 
                         string[:-1].decode("utf-8",
3206
 
                                            errors="replace"))
 
3181
            logger.debug("GnuTLS: %s", string[:-1])
3207
3182
 
3208
3183
        gnutls.global_set_log_function(debug_gnutls)
3209
3184
 
3584
3559
 
3585
3560
        try:
3586
3561
            with tempfile.NamedTemporaryFile(
3587
 
                    mode="wb",
 
3562
                    mode='wb',
3588
3563
                    suffix=".pickle",
3589
 
                    prefix="clients-",
 
3564
                    prefix='clients-',
3590
3565
                    dir=os.path.dirname(stored_state_path),
3591
3566
                    delete=False) as stored_state:
3592
3567
                pickle.dump((clients, client_settings), stored_state,
3679
3654
 
3680
3655
def should_only_run_tests():
3681
3656
    parser = argparse.ArgumentParser(add_help=False)
3682
 
    parser.add_argument("--check", action="store_true")
 
3657
    parser.add_argument("--check", action='store_true')
3683
3658
    args, unknown_args = parser.parse_known_args()
3684
3659
    run_tests = args.check
3685
3660
    if run_tests:
3693
3668
    tests.addTests(doctest.DocTestSuite())
3694
3669
    return tests
3695
3670
 
3696
 
if __name__ == "__main__":
 
3671
if __name__ == '__main__':
3697
3672
    try:
3698
3673
        if should_only_run_tests():
3699
3674
            # Call using ./mandos --check [--verbose]