/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: 2016-08-25 17:37:05 UTC
  • Revision ID: teddy@recompile.se-20160825173705-q2v6lban8ph9uw75
PEP8 compliance: mandos

* mandos: Add PEP8 compliance (as per the "pycodestyle" tool).

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-2019 Teddy Hogeborn
15
 
# Copyright © 2008-2019 Björn Påhlsson
16
 
#
17
 
# This file is part of Mandos.
18
 
#
19
 
# Mandos is free software: you can redistribute it and/or modify it
20
 
# under the terms of the GNU General Public License as published by
 
14
# Copyright © 2008-2016 Teddy Hogeborn
 
15
# Copyright © 2008-2016 Björn Påhlsson
 
16
#
 
17
# This program is free software: you can redistribute it and/or modify
 
18
# it under the terms of the GNU General Public License as published by
21
19
# the Free Software Foundation, either version 3 of the License, or
22
20
# (at your option) any later version.
23
21
#
24
 
#     Mandos is distributed in the hope that it will be useful, but
25
 
#     WITHOUT ANY WARRANTY; without even the implied warranty of
 
22
#     This program is distributed in the hope that it will be useful,
 
23
#     but WITHOUT ANY WARRANTY; without even the implied warranty of
26
24
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27
25
#     GNU General Public License for more details.
28
26
#
29
27
# You should have received a copy of the GNU General Public License
30
 
# along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
 
28
# along with this program.  If not, see
 
29
# <http://www.gnu.org/licenses/>.
31
30
#
32
31
# Contact the authors at <mandos@recompile.se>.
33
32
#
80
79
 
81
80
import dbus
82
81
import dbus.service
83
 
import gi
84
82
from gi.repository import GLib
85
83
from dbus.mainloop.glib import DBusGMainLoop
86
84
import ctypes
88
86
import xml.dom.minidom
89
87
import inspect
90
88
 
91
 
if sys.version_info.major == 2:
92
 
    __metaclass__ = type
93
 
 
94
89
# Try to find the value of SO_BINDTODEVICE:
95
90
try:
96
91
    # This is where SO_BINDTODEVICE is in Python 3.3 (or 3.4?) and
119
114
if sys.version_info.major == 2:
120
115
    str = unicode
121
116
 
122
 
if sys.version_info < (3, 2):
123
 
    configparser.Configparser = configparser.SafeConfigParser
124
 
 
125
 
version = "1.8.7"
 
117
version = "1.7.10"
126
118
stored_state_file = "clients.pickle"
127
119
 
128
120
logger = logging.getLogger()
186
178
    pass
187
179
 
188
180
 
189
 
class PGPEngine:
 
181
class PGPEngine(object):
190
182
    """A simple class for OpenPGP symmetric encryption & decryption"""
191
183
 
192
184
    def __init__(self):
282
274
 
283
275
 
284
276
# Pretend that we have an Avahi module
285
 
class avahi:
286
 
    """This isn't so much a class as it is a module-like namespace."""
 
277
class Avahi(object):
 
278
    """This isn't so much a class as it is a module-like namespace.
 
279
    It is instantiated once, and simulates having an Avahi module."""
287
280
    IF_UNSPEC = -1               # avahi-common/address.h
288
281
    PROTO_UNSPEC = -1            # avahi-common/address.h
289
282
    PROTO_INET = 0               # avahi-common/address.h
293
286
    DBUS_INTERFACE_SERVER = DBUS_NAME + ".Server"
294
287
    DBUS_PATH_SERVER = "/"
295
288
 
296
 
    @staticmethod
297
 
    def string_array_to_txt_array(t):
 
289
    def string_array_to_txt_array(self, t):
298
290
        return dbus.Array((dbus.ByteArray(s.encode("utf-8"))
299
291
                           for s in t), signature="ay")
300
292
    ENTRY_GROUP_ESTABLISHED = 2  # avahi-common/defs.h
305
297
    SERVER_RUNNING = 2           # avahi-common/defs.h
306
298
    SERVER_COLLISION = 3         # avahi-common/defs.h
307
299
    SERVER_FAILURE = 4           # avahi-common/defs.h
 
300
avahi = Avahi()
308
301
 
309
302
 
310
303
class AvahiError(Exception):
322
315
    pass
323
316
 
324
317
 
325
 
class AvahiService:
 
318
class AvahiService(object):
326
319
    """An Avahi (Zeroconf) service.
327
320
 
328
321
    Attributes:
502
495
class AvahiServiceToSyslog(AvahiService):
503
496
    def rename(self, *args, **kwargs):
504
497
        """Add the new name to the syslog messages"""
505
 
        ret = super(AvahiServiceToSyslog, self).rename(*args, **kwargs)
 
498
        ret = AvahiService.rename(self, *args, **kwargs)
506
499
        syslogger.setFormatter(logging.Formatter(
507
500
            'Mandos ({}) [%(process)d]: %(levelname)s: %(message)s'
508
501
            .format(self.name)))
510
503
 
511
504
 
512
505
# Pretend that we have a GnuTLS module
513
 
class gnutls:
514
 
    """This isn't so much a class as it is a module-like namespace."""
515
 
 
516
 
    library = ctypes.util.find_library("gnutls")
517
 
    if library is None:
518
 
        library = ctypes.util.find_library("gnutls-deb0")
519
 
    _library = ctypes.cdll.LoadLibrary(library)
520
 
    del library
 
506
class GnuTLS(object):
 
507
    """This isn't so much a class as it is a module-like namespace.
 
508
    It is instantiated once, and simulates having a GnuTLS module."""
 
509
 
 
510
    _library = ctypes.cdll.LoadLibrary(
 
511
        ctypes.util.find_library("gnutls"))
 
512
    _need_version = b"3.3.0"
 
513
 
 
514
    def __init__(self):
 
515
        # Need to use class name "GnuTLS" here, since this method is
 
516
        # called before the assignment to the "gnutls" global variable
 
517
        # happens.
 
518
        if GnuTLS.check_version(self._need_version) is None:
 
519
            raise GnuTLS.Error("Needs GnuTLS {} or later"
 
520
                               .format(self._need_version))
521
521
 
522
522
    # Unless otherwise indicated, the constants and types below are
523
523
    # all from the gnutls/gnutls.h C header file.
527
527
    E_INTERRUPTED = -52
528
528
    E_AGAIN = -28
529
529
    CRT_OPENPGP = 2
530
 
    CRT_RAWPK = 3
531
530
    CLIENT = 2
532
531
    SHUT_RDWR = 0
533
532
    CRD_CERTIFICATE = 1
534
533
    E_NO_CERTIFICATE_FOUND = -49
535
 
    X509_FMT_DER = 0
536
 
    NO_TICKETS = 1<<10
537
 
    ENABLE_RAWPK = 1<<18
538
 
    CTYPE_PEERS = 3
539
 
    KEYID_USE_SHA256 = 1        # gnutls/x509.h
540
534
    OPENPGP_FMT_RAW = 0         # gnutls/openpgp.h
541
535
 
542
536
    # Types
565
559
 
566
560
    # Exceptions
567
561
    class Error(Exception):
 
562
        # We need to use the class name "GnuTLS" here, since this
 
563
        # exception might be raised from within GnuTLS.__init__,
 
564
        # which is called before the assignment to the "gnutls"
 
565
        # global variable has happened.
568
566
        def __init__(self, message=None, code=None, args=()):
569
567
            # Default usage is by a message string, but if a return
570
568
            # code is passed, convert it to a string with
571
569
            # gnutls.strerror()
572
570
            self.code = code
573
571
            if message is None and code is not None:
574
 
                message = gnutls.strerror(code)
575
 
            return super(gnutls.Error, self).__init__(
 
572
                message = GnuTLS.strerror(code)
 
573
            return super(GnuTLS.Error, self).__init__(
576
574
                message, *args)
577
575
 
578
576
    class CertificateSecurityError(Error):
579
577
        pass
580
578
 
581
579
    # Classes
582
 
    class Credentials:
 
580
    class Credentials(object):
583
581
        def __init__(self):
584
582
            self._c_object = gnutls.certificate_credentials_t()
585
583
            gnutls.certificate_allocate_credentials(
589
587
        def __del__(self):
590
588
            gnutls.certificate_free_credentials(self._c_object)
591
589
 
592
 
    class ClientSession:
 
590
    class ClientSession(object):
593
591
        def __init__(self, socket, credentials=None):
594
592
            self._c_object = gnutls.session_t()
595
 
            gnutls_flags = gnutls.CLIENT
596
 
            if gnutls.check_version(b"3.5.6"):
597
 
                gnutls_flags |= gnutls.NO_TICKETS
598
 
            if gnutls.has_rawpk:
599
 
                gnutls_flags |= gnutls.ENABLE_RAWPK
600
 
            gnutls.init(ctypes.byref(self._c_object), gnutls_flags)
601
 
            del gnutls_flags
 
593
            gnutls.init(ctypes.byref(self._c_object), gnutls.CLIENT)
602
594
            gnutls.set_default_priority(self._c_object)
603
595
            gnutls.transport_set_ptr(self._c_object, socket.fileno())
604
596
            gnutls.handshake_set_private_extensions(self._c_object,
736
728
    check_version.argtypes = [ctypes.c_char_p]
737
729
    check_version.restype = ctypes.c_char_p
738
730
 
739
 
    _need_version = b"3.3.0"
740
 
    if check_version(_need_version) is None:
741
 
        raise self.Error("Needs GnuTLS {} or later"
742
 
                         .format(_need_version))
743
 
 
744
 
    _tls_rawpk_version = b"3.6.6"
745
 
    has_rawpk = bool(check_version(_tls_rawpk_version))
746
 
 
747
 
    if has_rawpk:
748
 
        # Types
749
 
        class pubkey_st(ctypes.Structure):
750
 
            _fields = []
751
 
        pubkey_t = ctypes.POINTER(pubkey_st)
752
 
 
753
 
        x509_crt_fmt_t = ctypes.c_int
754
 
 
755
 
        # All the function declarations below are from gnutls/abstract.h
756
 
        pubkey_init = _library.gnutls_pubkey_init
757
 
        pubkey_init.argtypes = [ctypes.POINTER(pubkey_t)]
758
 
        pubkey_init.restype = _error_code
759
 
 
760
 
        pubkey_import = _library.gnutls_pubkey_import
761
 
        pubkey_import.argtypes = [pubkey_t, ctypes.POINTER(datum_t),
762
 
                                  x509_crt_fmt_t]
763
 
        pubkey_import.restype = _error_code
764
 
 
765
 
        pubkey_get_key_id = _library.gnutls_pubkey_get_key_id
766
 
        pubkey_get_key_id.argtypes = [pubkey_t, ctypes.c_int,
767
 
                                      ctypes.POINTER(ctypes.c_ubyte),
768
 
                                      ctypes.POINTER(ctypes.c_size_t)]
769
 
        pubkey_get_key_id.restype = _error_code
770
 
 
771
 
        pubkey_deinit = _library.gnutls_pubkey_deinit
772
 
        pubkey_deinit.argtypes = [pubkey_t]
773
 
        pubkey_deinit.restype = None
774
 
    else:
775
 
        # All the function declarations below are from gnutls/openpgp.h
776
 
 
777
 
        openpgp_crt_init = _library.gnutls_openpgp_crt_init
778
 
        openpgp_crt_init.argtypes = [ctypes.POINTER(openpgp_crt_t)]
779
 
        openpgp_crt_init.restype = _error_code
780
 
 
781
 
        openpgp_crt_import = _library.gnutls_openpgp_crt_import
782
 
        openpgp_crt_import.argtypes = [openpgp_crt_t,
783
 
                                       ctypes.POINTER(datum_t),
784
 
                                       openpgp_crt_fmt_t]
785
 
        openpgp_crt_import.restype = _error_code
786
 
 
787
 
        openpgp_crt_verify_self = _library.gnutls_openpgp_crt_verify_self
788
 
        openpgp_crt_verify_self.argtypes = [openpgp_crt_t, ctypes.c_uint,
789
 
                                            ctypes.POINTER(ctypes.c_uint)]
790
 
        openpgp_crt_verify_self.restype = _error_code
791
 
 
792
 
        openpgp_crt_deinit = _library.gnutls_openpgp_crt_deinit
793
 
        openpgp_crt_deinit.argtypes = [openpgp_crt_t]
794
 
        openpgp_crt_deinit.restype = None
795
 
 
796
 
        openpgp_crt_get_fingerprint = (
797
 
            _library.gnutls_openpgp_crt_get_fingerprint)
798
 
        openpgp_crt_get_fingerprint.argtypes = [openpgp_crt_t,
799
 
                                                ctypes.c_void_p,
800
 
                                                ctypes.POINTER(
801
 
                                                    ctypes.c_size_t)]
802
 
        openpgp_crt_get_fingerprint.restype = _error_code
803
 
 
804
 
    if check_version(b"3.6.4"):
805
 
        certificate_type_get2 = _library.gnutls_certificate_type_get2
806
 
        certificate_type_get2.argtypes = [session_t, ctypes.c_int]
807
 
        certificate_type_get2.restype = _error_code
 
731
    # All the function declarations below are from gnutls/openpgp.h
 
732
 
 
733
    openpgp_crt_init = _library.gnutls_openpgp_crt_init
 
734
    openpgp_crt_init.argtypes = [ctypes.POINTER(openpgp_crt_t)]
 
735
    openpgp_crt_init.restype = _error_code
 
736
 
 
737
    openpgp_crt_import = _library.gnutls_openpgp_crt_import
 
738
    openpgp_crt_import.argtypes = [openpgp_crt_t,
 
739
                                   ctypes.POINTER(datum_t),
 
740
                                   openpgp_crt_fmt_t]
 
741
    openpgp_crt_import.restype = _error_code
 
742
 
 
743
    openpgp_crt_verify_self = _library.gnutls_openpgp_crt_verify_self
 
744
    openpgp_crt_verify_self.argtypes = [openpgp_crt_t, ctypes.c_uint,
 
745
                                        ctypes.POINTER(ctypes.c_uint)]
 
746
    openpgp_crt_verify_self.restype = _error_code
 
747
 
 
748
    openpgp_crt_deinit = _library.gnutls_openpgp_crt_deinit
 
749
    openpgp_crt_deinit.argtypes = [openpgp_crt_t]
 
750
    openpgp_crt_deinit.restype = None
 
751
 
 
752
    openpgp_crt_get_fingerprint = (
 
753
        _library.gnutls_openpgp_crt_get_fingerprint)
 
754
    openpgp_crt_get_fingerprint.argtypes = [openpgp_crt_t,
 
755
                                            ctypes.c_void_p,
 
756
                                            ctypes.POINTER(
 
757
                                                ctypes.c_size_t)]
 
758
    openpgp_crt_get_fingerprint.restype = _error_code
808
759
 
809
760
    # Remove non-public functions
810
761
    del _error_code, _retry_on_error
 
762
# Create the global "gnutls" object, simulating a module
 
763
gnutls = GnuTLS()
811
764
 
812
765
 
813
766
def call_pipe(connection,       # : multiprocessing.Connection
821
774
    connection.close()
822
775
 
823
776
 
824
 
class Client:
 
777
class Client(object):
825
778
    """A representation of a client host served by this server.
826
779
 
827
780
    Attributes:
828
781
    approved:   bool(); 'None' if not yet approved/disapproved
829
782
    approval_delay: datetime.timedelta(); Time to wait for approval
830
783
    approval_duration: datetime.timedelta(); Duration of one approval
831
 
    checker: multiprocessing.Process(); a running checker process used
832
 
             to see if the client lives. 'None' if no process is
833
 
             running.
 
784
    checker:    subprocess.Popen(); a running checker process used
 
785
                                    to see if the client lives.
 
786
                                    'None' if no process is running.
834
787
    checker_callback_tag: a GLib event source tag, or None
835
788
    checker_command: string; External command which is run to check
836
789
                     if client lives.  %() expansions are done at
844
797
    disable_initiator_tag: a GLib event source tag, or None
845
798
    enabled:    bool()
846
799
    fingerprint: string (40 or 32 hexadecimal digits); used to
847
 
                 uniquely identify an OpenPGP client
848
 
    key_id: string (64 hexadecimal digits); used to uniquely identify
849
 
            a client using raw public keys
 
800
                 uniquely identify the client
850
801
    host:       string; available for use by the checker command
851
802
    interval:   datetime.timedelta(); How often to start a new checker
852
803
    last_approval_request: datetime.datetime(); (UTC) or None
870
821
    """
871
822
 
872
823
    runtime_expansions = ("approval_delay", "approval_duration",
873
 
                          "created", "enabled", "expires", "key_id",
 
824
                          "created", "enabled", "expires",
874
825
                          "fingerprint", "host", "interval",
875
826
                          "last_approval_request", "last_checked_ok",
876
827
                          "last_enabled", "name", "timeout")
906
857
            client["enabled"] = config.getboolean(client_name,
907
858
                                                  "enabled")
908
859
 
909
 
            # Uppercase and remove spaces from key_id and fingerprint
910
 
            # for later comparison purposes with return value from the
911
 
            # key_id() and fingerprint() functions
912
 
            client["key_id"] = (section.get("key_id", "").upper()
913
 
                                .replace(" ", ""))
 
860
            # Uppercase and remove spaces from fingerprint for later
 
861
            # comparison purposes with return value from the
 
862
            # fingerprint() function
914
863
            client["fingerprint"] = (section["fingerprint"].upper()
915
864
                                     .replace(" ", ""))
916
865
            if "secret" in section:
960
909
            self.expires = None
961
910
 
962
911
        logger.debug("Creating client %r", self.name)
963
 
        logger.debug("  Key ID: %s", self.key_id)
964
912
        logger.debug("  Fingerprint: %s", self.fingerprint)
965
913
        self.created = settings.get("created",
966
914
                                    datetime.datetime.utcnow())
1043
991
    def checker_callback(self, source, condition, connection,
1044
992
                         command):
1045
993
        """The checker has completed, so take appropriate actions."""
 
994
        self.checker_callback_tag = None
 
995
        self.checker = None
1046
996
        # Read return code from connection (see call_pipe)
1047
997
        returncode = connection.recv()
1048
998
        connection.close()
1049
 
        self.checker.join()
1050
 
        self.checker_callback_tag = None
1051
 
        self.checker = None
1052
999
 
1053
1000
        if returncode >= 0:
1054
1001
            self.last_checker_status = returncode
1511
1458
                         exc_info=error)
1512
1459
        return xmlstring
1513
1460
 
1514
 
 
1515
1461
try:
1516
1462
    dbus.OBJECT_MANAGER_IFACE
1517
1463
except AttributeError:
2049
1995
    def Name_dbus_property(self):
2050
1996
        return dbus.String(self.name)
2051
1997
 
2052
 
    # KeyID - property
2053
 
    @dbus_annotations(
2054
 
        {"org.freedesktop.DBus.Property.EmitsChangedSignal": "const"})
2055
 
    @dbus_service_property(_interface, signature="s", access="read")
2056
 
    def KeyID_dbus_property(self):
2057
 
        return dbus.String(self.key_id)
2058
 
 
2059
1998
    # Fingerprint - property
2060
1999
    @dbus_annotations(
2061
2000
        {"org.freedesktop.DBus.Property.EmitsChangedSignal": "const"})
2216
2155
    del _interface
2217
2156
 
2218
2157
 
2219
 
class ProxyClient:
2220
 
    def __init__(self, child_pipe, key_id, fpr, address):
 
2158
class ProxyClient(object):
 
2159
    def __init__(self, child_pipe, fpr, address):
2221
2160
        self._pipe = child_pipe
2222
 
        self._pipe.send(('init', key_id, fpr, address))
 
2161
        self._pipe.send(('init', fpr, address))
2223
2162
        if not self._pipe.recv():
2224
 
            raise KeyError(key_id or fpr)
 
2163
            raise KeyError(fpr)
2225
2164
 
2226
2165
    def __getattribute__(self, name):
2227
2166
        if name == '_pipe':
2294
2233
 
2295
2234
            approval_required = False
2296
2235
            try:
2297
 
                if gnutls.has_rawpk:
2298
 
                    fpr = b""
2299
 
                    try:
2300
 
                        key_id = self.key_id(
2301
 
                            self.peer_certificate(session))
2302
 
                    except (TypeError, gnutls.Error) as error:
2303
 
                        logger.warning("Bad certificate: %s", error)
2304
 
                        return
2305
 
                    logger.debug("Key ID: %s", key_id)
2306
 
 
2307
 
                else:
2308
 
                    key_id = b""
2309
 
                    try:
2310
 
                        fpr = self.fingerprint(
2311
 
                            self.peer_certificate(session))
2312
 
                    except (TypeError, gnutls.Error) as error:
2313
 
                        logger.warning("Bad certificate: %s", error)
2314
 
                        return
2315
 
                    logger.debug("Fingerprint: %s", fpr)
2316
 
 
2317
 
                try:
2318
 
                    client = ProxyClient(child_pipe, key_id, fpr,
 
2236
                try:
 
2237
                    fpr = self.fingerprint(
 
2238
                        self.peer_certificate(session))
 
2239
                except (TypeError, gnutls.Error) as error:
 
2240
                    logger.warning("Bad certificate: %s", error)
 
2241
                    return
 
2242
                logger.debug("Fingerprint: %s", fpr)
 
2243
 
 
2244
                try:
 
2245
                    client = ProxyClient(child_pipe, fpr,
2319
2246
                                         self.client_address)
2320
2247
                except KeyError:
2321
2248
                    return
2398
2325
 
2399
2326
    @staticmethod
2400
2327
    def peer_certificate(session):
2401
 
        "Return the peer's certificate as a bytestring"
2402
 
        try:
2403
 
            cert_type = gnutls.certificate_type_get2(session._c_object,
2404
 
                                                     gnutls.CTYPE_PEERS)
2405
 
        except AttributeError:
2406
 
            cert_type = gnutls.certificate_type_get(session._c_object)
2407
 
        if gnutls.has_rawpk:
2408
 
            valid_cert_types = frozenset((gnutls.CRT_RAWPK,))
2409
 
        else:
2410
 
            valid_cert_types = frozenset((gnutls.CRT_OPENPGP,))
2411
 
        # If not a valid certificate type...
2412
 
        if cert_type not in valid_cert_types:
2413
 
            logger.info("Cert type %r not in %r", cert_type,
2414
 
                        valid_cert_types)
 
2328
        "Return the peer's OpenPGP certificate as a bytestring"
 
2329
        # If not an OpenPGP certificate...
 
2330
        if (gnutls.certificate_type_get(session._c_object)
 
2331
            != gnutls.CRT_OPENPGP):
2415
2332
            # ...return invalid data
2416
2333
            return b""
2417
2334
        list_size = ctypes.c_uint(1)
2425
2342
        return ctypes.string_at(cert.data, cert.size)
2426
2343
 
2427
2344
    @staticmethod
2428
 
    def key_id(certificate):
2429
 
        "Convert a certificate bytestring to a hexdigit key ID"
2430
 
        # New GnuTLS "datum" with the public key
2431
 
        datum = gnutls.datum_t(
2432
 
            ctypes.cast(ctypes.c_char_p(certificate),
2433
 
                        ctypes.POINTER(ctypes.c_ubyte)),
2434
 
            ctypes.c_uint(len(certificate)))
2435
 
        # XXX all these need to be created in the gnutls "module"
2436
 
        # New empty GnuTLS certificate
2437
 
        pubkey = gnutls.pubkey_t()
2438
 
        gnutls.pubkey_init(ctypes.byref(pubkey))
2439
 
        # Import the raw public key into the certificate
2440
 
        gnutls.pubkey_import(pubkey,
2441
 
                             ctypes.byref(datum),
2442
 
                             gnutls.X509_FMT_DER)
2443
 
        # New buffer for the key ID
2444
 
        buf = ctypes.create_string_buffer(32)
2445
 
        buf_len = ctypes.c_size_t(len(buf))
2446
 
        # Get the key ID from the raw public key into the buffer
2447
 
        gnutls.pubkey_get_key_id(pubkey,
2448
 
                                 gnutls.KEYID_USE_SHA256,
2449
 
                                 ctypes.cast(ctypes.byref(buf),
2450
 
                                             ctypes.POINTER(ctypes.c_ubyte)),
2451
 
                                 ctypes.byref(buf_len))
2452
 
        # Deinit the certificate
2453
 
        gnutls.pubkey_deinit(pubkey)
2454
 
 
2455
 
        # Convert the buffer to a Python bytestring
2456
 
        key_id = ctypes.string_at(buf, buf_len.value)
2457
 
        # Convert the bytestring to hexadecimal notation
2458
 
        hex_key_id = binascii.hexlify(key_id).upper()
2459
 
        return hex_key_id
2460
 
 
2461
 
    @staticmethod
2462
2345
    def fingerprint(openpgp):
2463
2346
        "Convert an OpenPGP bytestring to a hexdigit fingerprint"
2464
2347
        # New GnuTLS "datum" with the OpenPGP public key
2478
2361
                                       ctypes.byref(crtverify))
2479
2362
        if crtverify.value != 0:
2480
2363
            gnutls.openpgp_crt_deinit(crt)
2481
 
            raise gnutls.CertificateSecurityError(code
2482
 
                                                  =crtverify.value)
 
2364
            raise gnutls.CertificateSecurityError("Verify failed")
2483
2365
        # New buffer for the fingerprint
2484
2366
        buf = ctypes.create_string_buffer(20)
2485
2367
        buf_len = ctypes.c_size_t()
2495
2377
        return hex_fpr
2496
2378
 
2497
2379
 
2498
 
class MultiprocessingMixIn:
 
2380
class MultiprocessingMixIn(object):
2499
2381
    """Like socketserver.ThreadingMixIn, but with multiprocessing"""
2500
2382
 
2501
2383
    def sub_process_main(self, request, address):
2513
2395
        return proc
2514
2396
 
2515
2397
 
2516
 
class MultiprocessingMixInWithPipe(MultiprocessingMixIn):
 
2398
class MultiprocessingMixInWithPipe(MultiprocessingMixIn, object):
2517
2399
    """ adds a pipe to the MixIn """
2518
2400
 
2519
2401
    def process_request(self, request, client_address):
2534
2416
 
2535
2417
 
2536
2418
class IPv6_TCPServer(MultiprocessingMixInWithPipe,
2537
 
                     socketserver.TCPServer):
 
2419
                     socketserver.TCPServer, object):
2538
2420
    """IPv6-capable TCP server.  Accepts 'None' as address and/or port
2539
2421
 
2540
2422
    Attributes:
2613
2495
                    raise
2614
2496
        # Only bind(2) the socket if we really need to.
2615
2497
        if self.server_address[0] or self.server_address[1]:
2616
 
            if self.server_address[1]:
2617
 
                self.allow_reuse_address = True
2618
2498
            if not self.server_address[0]:
2619
2499
                if self.address_family == socket.AF_INET6:
2620
2500
                    any_address = "::"  # in6addr_any
2694
2574
        command = request[0]
2695
2575
 
2696
2576
        if command == 'init':
2697
 
            key_id = request[1].decode("ascii")
2698
 
            fpr = request[2].decode("ascii")
2699
 
            address = request[3]
 
2577
            fpr = request[1]
 
2578
            address = request[2]
2700
2579
 
2701
2580
            for c in self.clients.values():
2702
 
                if key_id == "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855":
2703
 
                    continue
2704
 
                if key_id and c.key_id == key_id:
2705
 
                    client = c
2706
 
                    break
2707
 
                if fpr and c.fingerprint == fpr:
 
2581
                if c.fingerprint == fpr:
2708
2582
                    client = c
2709
2583
                    break
2710
2584
            else:
2711
 
                logger.info("Client not found for key ID: %s, address"
2712
 
                            ": %s", key_id or fpr, address)
 
2585
                logger.info("Client not found for fingerprint: %s, ad"
 
2586
                            "dress: %s", fpr, address)
2713
2587
                if self.use_dbus:
2714
2588
                    # Emit D-Bus signal
2715
 
                    mandos_dbus_service.ClientNotFound(key_id or fpr,
 
2589
                    mandos_dbus_service.ClientNotFound(fpr,
2716
2590
                                                       address[0])
2717
2591
                parent_pipe.send(False)
2718
2592
                return False
2981
2855
        sys.exit(os.EX_OK if fail_count == 0 else 1)
2982
2856
 
2983
2857
    # Default values for config file for server-global settings
2984
 
    if gnutls.has_rawpk:
2985
 
        priority = ("SECURE128:!CTYPE-X.509:+CTYPE-RAWPK:!RSA"
2986
 
                    ":!VERS-ALL:+VERS-TLS1.3:%PROFILE_ULTRA")
2987
 
    else:
2988
 
        priority = ("SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP:!RSA"
2989
 
                    ":+SIGN-DSA-SHA256")
2990
2858
    server_defaults = {"interface": "",
2991
2859
                       "address": "",
2992
2860
                       "port": "",
2993
2861
                       "debug": "False",
2994
 
                       "priority": priority,
 
2862
                       "priority":
 
2863
                       "SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP:!RSA"
 
2864
                       ":+SIGN-DSA-SHA256",
2995
2865
                       "servicename": "Mandos",
2996
2866
                       "use_dbus": "True",
2997
2867
                       "use_ipv6": "True",
3002
2872
                       "foreground": "False",
3003
2873
                       "zeroconf": "True",
3004
2874
                       }
3005
 
    del priority
3006
2875
 
3007
2876
    # Parse config file for server-global settings
3008
 
    server_config = configparser.ConfigParser(server_defaults)
 
2877
    server_config = configparser.SafeConfigParser(server_defaults)
3009
2878
    del server_defaults
3010
2879
    server_config.read(os.path.join(options.configdir, "mandos.conf"))
3011
 
    # Convert the ConfigParser object to a dict
 
2880
    # Convert the SafeConfigParser object to a dict
3012
2881
    server_settings = server_config.defaults()
3013
2882
    # Use the appropriate methods on the non-string config options
3014
 
    for option in ("debug", "use_dbus", "use_ipv6", "restore",
3015
 
                   "foreground", "zeroconf"):
 
2883
    for option in ("debug", "use_dbus", "use_ipv6", "foreground"):
3016
2884
        server_settings[option] = server_config.getboolean("DEFAULT",
3017
2885
                                                           option)
3018
2886
    if server_settings["port"]:
3086
2954
                                  server_settings["servicename"])))
3087
2955
 
3088
2956
    # Parse config file with clients
3089
 
    client_config = configparser.ConfigParser(Client.client_defaults)
 
2957
    client_config = configparser.SafeConfigParser(Client
 
2958
                                                  .client_defaults)
3090
2959
    client_config.read(os.path.join(server_settings["configdir"],
3091
2960
                                    "clients.conf"))
3092
2961
 
3163
3032
        # Close all input and output, do double fork, etc.
3164
3033
        daemon()
3165
3034
 
3166
 
    if gi.version_info < (3, 10, 2):
3167
 
        # multiprocessing will use threads, so before we use GLib we
3168
 
        # need to inform GLib that threads will be used.
3169
 
        GLib.threads_init()
 
3035
    # multiprocessing will use threads, so before we use GLib we need
 
3036
    # to inform GLib that threads will be used.
 
3037
    GLib.threads_init()
3170
3038
 
3171
3039
    global main_loop
3172
3040
    # From the Avahi example code
3252
3120
                        for k in ("name", "host"):
3253
3121
                            if isinstance(value[k], bytes):
3254
3122
                                value[k] = value[k].decode("utf-8")
3255
 
                        if "key_id" not in value:
3256
 
                            value["key_id"] = ""
3257
 
                        elif "fingerprint" not in value:
3258
 
                            value["fingerprint"] = ""
3259
3123
                    #  old_client_settings
3260
3124
                    # .keys()
3261
3125
                    old_client_settings = {
3398
3262
                pass
3399
3263
 
3400
3264
            @dbus.service.signal(_interface, signature="ss")
3401
 
            def ClientNotFound(self, key_id, address):
 
3265
            def ClientNotFound(self, fingerprint, address):
3402
3266
                "D-Bus signal"
3403
3267
                pass
3404
3268