/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: 2018-02-06 20:03:50 UTC
  • Revision ID: teddy@recompile.se-20180206200350-jzvorueb731xkph3
Update Debian Debhelper compatibility version.

* (debian/compat): Change to "10".

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
 
14
# Copyright © 2008-2017 Teddy Hogeborn
 
15
# Copyright © 2008-2017 Björn Påhlsson
16
16
#
17
17
# This file is part of Mandos.
18
18
#
80
80
 
81
81
import dbus
82
82
import dbus.service
83
 
import gi
84
83
from gi.repository import GLib
85
84
from dbus.mainloop.glib import DBusGMainLoop
86
85
import ctypes
88
87
import xml.dom.minidom
89
88
import inspect
90
89
 
91
 
if sys.version_info.major == 2:
92
 
    __metaclass__ = type
93
 
 
94
90
# Try to find the value of SO_BINDTODEVICE:
95
91
try:
96
92
    # This is where SO_BINDTODEVICE is in Python 3.3 (or 3.4?) and
119
115
if sys.version_info.major == 2:
120
116
    str = unicode
121
117
 
122
 
if sys.version_info < (3, 2):
123
 
    configparser.Configparser = configparser.SafeConfigParser
124
 
 
125
 
version = "1.8.7"
 
118
version = "1.7.16"
126
119
stored_state_file = "clients.pickle"
127
120
 
128
121
logger = logging.getLogger()
186
179
    pass
187
180
 
188
181
 
189
 
class PGPEngine:
 
182
class PGPEngine(object):
190
183
    """A simple class for OpenPGP symmetric encryption & decryption"""
191
184
 
192
185
    def __init__(self):
282
275
 
283
276
 
284
277
# 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."""
 
278
class Avahi(object):
 
279
    """This isn't so much a class as it is a module-like namespace.
 
280
    It is instantiated once, and simulates having an Avahi module."""
287
281
    IF_UNSPEC = -1               # avahi-common/address.h
288
282
    PROTO_UNSPEC = -1            # avahi-common/address.h
289
283
    PROTO_INET = 0               # avahi-common/address.h
293
287
    DBUS_INTERFACE_SERVER = DBUS_NAME + ".Server"
294
288
    DBUS_PATH_SERVER = "/"
295
289
 
296
 
    @staticmethod
297
 
    def string_array_to_txt_array(t):
 
290
    def string_array_to_txt_array(self, t):
298
291
        return dbus.Array((dbus.ByteArray(s.encode("utf-8"))
299
292
                           for s in t), signature="ay")
300
293
    ENTRY_GROUP_ESTABLISHED = 2  # avahi-common/defs.h
305
298
    SERVER_RUNNING = 2           # avahi-common/defs.h
306
299
    SERVER_COLLISION = 3         # avahi-common/defs.h
307
300
    SERVER_FAILURE = 4           # avahi-common/defs.h
 
301
avahi = Avahi()
308
302
 
309
303
 
310
304
class AvahiError(Exception):
322
316
    pass
323
317
 
324
318
 
325
 
class AvahiService:
 
319
class AvahiService(object):
326
320
    """An Avahi (Zeroconf) service.
327
321
 
328
322
    Attributes:
502
496
class AvahiServiceToSyslog(AvahiService):
503
497
    def rename(self, *args, **kwargs):
504
498
        """Add the new name to the syslog messages"""
505
 
        ret = super(AvahiServiceToSyslog, self).rename(*args, **kwargs)
 
499
        ret = super(AvahiServiceToSyslog, self).rename(self, *args,
 
500
                                                       **kwargs)
506
501
        syslogger.setFormatter(logging.Formatter(
507
502
            'Mandos ({}) [%(process)d]: %(levelname)s: %(message)s'
508
503
            .format(self.name)))
510
505
 
511
506
 
512
507
# 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."""
 
508
class GnuTLS(object):
 
509
    """This isn't so much a class as it is a module-like namespace.
 
510
    It is instantiated once, and simulates having a GnuTLS module."""
515
511
 
516
512
    library = ctypes.util.find_library("gnutls")
517
513
    if library is None:
518
514
        library = ctypes.util.find_library("gnutls-deb0")
519
515
    _library = ctypes.cdll.LoadLibrary(library)
520
516
    del library
 
517
    _need_version = b"3.3.0"
 
518
 
 
519
    def __init__(self):
 
520
        # Need to use "self" here, since this method is called before
 
521
        # the assignment to the "gnutls" global variable happens.
 
522
        if self.check_version(self._need_version) is None:
 
523
            raise self.Error("Needs GnuTLS {} or later"
 
524
                             .format(self._need_version))
521
525
 
522
526
    # Unless otherwise indicated, the constants and types below are
523
527
    # all from the gnutls/gnutls.h C header file.
527
531
    E_INTERRUPTED = -52
528
532
    E_AGAIN = -28
529
533
    CRT_OPENPGP = 2
530
 
    CRT_RAWPK = 3
531
534
    CLIENT = 2
532
535
    SHUT_RDWR = 0
533
536
    CRD_CERTIFICATE = 1
534
537
    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
538
    OPENPGP_FMT_RAW = 0         # gnutls/openpgp.h
541
539
 
542
540
    # Types
565
563
 
566
564
    # Exceptions
567
565
    class Error(Exception):
 
566
        # We need to use the class name "GnuTLS" here, since this
 
567
        # exception might be raised from within GnuTLS.__init__,
 
568
        # which is called before the assignment to the "gnutls"
 
569
        # global variable has happened.
568
570
        def __init__(self, message=None, code=None, args=()):
569
571
            # Default usage is by a message string, but if a return
570
572
            # code is passed, convert it to a string with
571
573
            # gnutls.strerror()
572
574
            self.code = code
573
575
            if message is None and code is not None:
574
 
                message = gnutls.strerror(code)
575
 
            return super(gnutls.Error, self).__init__(
 
576
                message = GnuTLS.strerror(code)
 
577
            return super(GnuTLS.Error, self).__init__(
576
578
                message, *args)
577
579
 
578
580
    class CertificateSecurityError(Error):
579
581
        pass
580
582
 
581
583
    # Classes
582
 
    class Credentials:
 
584
    class Credentials(object):
583
585
        def __init__(self):
584
586
            self._c_object = gnutls.certificate_credentials_t()
585
587
            gnutls.certificate_allocate_credentials(
589
591
        def __del__(self):
590
592
            gnutls.certificate_free_credentials(self._c_object)
591
593
 
592
 
    class ClientSession:
 
594
    class ClientSession(object):
593
595
        def __init__(self, socket, credentials=None):
594
596
            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
 
597
            gnutls.init(ctypes.byref(self._c_object), gnutls.CLIENT)
602
598
            gnutls.set_default_priority(self._c_object)
603
599
            gnutls.transport_set_ptr(self._c_object, socket.fileno())
604
600
            gnutls.handshake_set_private_extensions(self._c_object,
736
732
    check_version.argtypes = [ctypes.c_char_p]
737
733
    check_version.restype = ctypes.c_char_p
738
734
 
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
 
735
    # All the function declarations below are from gnutls/openpgp.h
 
736
 
 
737
    openpgp_crt_init = _library.gnutls_openpgp_crt_init
 
738
    openpgp_crt_init.argtypes = [ctypes.POINTER(openpgp_crt_t)]
 
739
    openpgp_crt_init.restype = _error_code
 
740
 
 
741
    openpgp_crt_import = _library.gnutls_openpgp_crt_import
 
742
    openpgp_crt_import.argtypes = [openpgp_crt_t,
 
743
                                   ctypes.POINTER(datum_t),
 
744
                                   openpgp_crt_fmt_t]
 
745
    openpgp_crt_import.restype = _error_code
 
746
 
 
747
    openpgp_crt_verify_self = _library.gnutls_openpgp_crt_verify_self
 
748
    openpgp_crt_verify_self.argtypes = [openpgp_crt_t, ctypes.c_uint,
 
749
                                        ctypes.POINTER(ctypes.c_uint)]
 
750
    openpgp_crt_verify_self.restype = _error_code
 
751
 
 
752
    openpgp_crt_deinit = _library.gnutls_openpgp_crt_deinit
 
753
    openpgp_crt_deinit.argtypes = [openpgp_crt_t]
 
754
    openpgp_crt_deinit.restype = None
 
755
 
 
756
    openpgp_crt_get_fingerprint = (
 
757
        _library.gnutls_openpgp_crt_get_fingerprint)
 
758
    openpgp_crt_get_fingerprint.argtypes = [openpgp_crt_t,
 
759
                                            ctypes.c_void_p,
 
760
                                            ctypes.POINTER(
 
761
                                                ctypes.c_size_t)]
 
762
    openpgp_crt_get_fingerprint.restype = _error_code
808
763
 
809
764
    # Remove non-public functions
810
765
    del _error_code, _retry_on_error
 
766
# Create the global "gnutls" object, simulating a module
 
767
gnutls = GnuTLS()
811
768
 
812
769
 
813
770
def call_pipe(connection,       # : multiprocessing.Connection
821
778
    connection.close()
822
779
 
823
780
 
824
 
class Client:
 
781
class Client(object):
825
782
    """A representation of a client host served by this server.
826
783
 
827
784
    Attributes:
828
785
    approved:   bool(); 'None' if not yet approved/disapproved
829
786
    approval_delay: datetime.timedelta(); Time to wait for approval
830
787
    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.
 
788
    checker:    subprocess.Popen(); a running checker process used
 
789
                                    to see if the client lives.
 
790
                                    'None' if no process is running.
834
791
    checker_callback_tag: a GLib event source tag, or None
835
792
    checker_command: string; External command which is run to check
836
793
                     if client lives.  %() expansions are done at
844
801
    disable_initiator_tag: a GLib event source tag, or None
845
802
    enabled:    bool()
846
803
    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
 
804
                 uniquely identify the client
850
805
    host:       string; available for use by the checker command
851
806
    interval:   datetime.timedelta(); How often to start a new checker
852
807
    last_approval_request: datetime.datetime(); (UTC) or None
870
825
    """
871
826
 
872
827
    runtime_expansions = ("approval_delay", "approval_duration",
873
 
                          "created", "enabled", "expires", "key_id",
 
828
                          "created", "enabled", "expires",
874
829
                          "fingerprint", "host", "interval",
875
830
                          "last_approval_request", "last_checked_ok",
876
831
                          "last_enabled", "name", "timeout")
906
861
            client["enabled"] = config.getboolean(client_name,
907
862
                                                  "enabled")
908
863
 
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(" ", ""))
 
864
            # Uppercase and remove spaces from fingerprint for later
 
865
            # comparison purposes with return value from the
 
866
            # fingerprint() function
914
867
            client["fingerprint"] = (section["fingerprint"].upper()
915
868
                                     .replace(" ", ""))
916
869
            if "secret" in section:
960
913
            self.expires = None
961
914
 
962
915
        logger.debug("Creating client %r", self.name)
963
 
        logger.debug("  Key ID: %s", self.key_id)
964
916
        logger.debug("  Fingerprint: %s", self.fingerprint)
965
917
        self.created = settings.get("created",
966
918
                                    datetime.datetime.utcnow())
1043
995
    def checker_callback(self, source, condition, connection,
1044
996
                         command):
1045
997
        """The checker has completed, so take appropriate actions."""
 
998
        self.checker_callback_tag = None
 
999
        self.checker = None
1046
1000
        # Read return code from connection (see call_pipe)
1047
1001
        returncode = connection.recv()
1048
1002
        connection.close()
1049
 
        self.checker.join()
1050
 
        self.checker_callback_tag = None
1051
 
        self.checker = None
1052
1003
 
1053
1004
        if returncode >= 0:
1054
1005
            self.last_checker_status = returncode
2049
2000
    def Name_dbus_property(self):
2050
2001
        return dbus.String(self.name)
2051
2002
 
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
2003
    # Fingerprint - property
2060
2004
    @dbus_annotations(
2061
2005
        {"org.freedesktop.DBus.Property.EmitsChangedSignal": "const"})
2216
2160
    del _interface
2217
2161
 
2218
2162
 
2219
 
class ProxyClient:
2220
 
    def __init__(self, child_pipe, key_id, fpr, address):
 
2163
class ProxyClient(object):
 
2164
    def __init__(self, child_pipe, fpr, address):
2221
2165
        self._pipe = child_pipe
2222
 
        self._pipe.send(('init', key_id, fpr, address))
 
2166
        self._pipe.send(('init', fpr, address))
2223
2167
        if not self._pipe.recv():
2224
 
            raise KeyError(key_id or fpr)
 
2168
            raise KeyError(fpr)
2225
2169
 
2226
2170
    def __getattribute__(self, name):
2227
2171
        if name == '_pipe':
2294
2238
 
2295
2239
            approval_required = False
2296
2240
            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,
 
2241
                try:
 
2242
                    fpr = self.fingerprint(
 
2243
                        self.peer_certificate(session))
 
2244
                except (TypeError, gnutls.Error) as error:
 
2245
                    logger.warning("Bad certificate: %s", error)
 
2246
                    return
 
2247
                logger.debug("Fingerprint: %s", fpr)
 
2248
 
 
2249
                try:
 
2250
                    client = ProxyClient(child_pipe, fpr,
2319
2251
                                         self.client_address)
2320
2252
                except KeyError:
2321
2253
                    return
2398
2330
 
2399
2331
    @staticmethod
2400
2332
    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)
 
2333
        "Return the peer's OpenPGP certificate as a bytestring"
 
2334
        # If not an OpenPGP certificate...
 
2335
        if (gnutls.certificate_type_get(session._c_object)
 
2336
            != gnutls.CRT_OPENPGP):
2415
2337
            # ...return invalid data
2416
2338
            return b""
2417
2339
        list_size = ctypes.c_uint(1)
2425
2347
        return ctypes.string_at(cert.data, cert.size)
2426
2348
 
2427
2349
    @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
2350
    def fingerprint(openpgp):
2463
2351
        "Convert an OpenPGP bytestring to a hexdigit fingerprint"
2464
2352
        # New GnuTLS "datum" with the OpenPGP public key
2478
2366
                                       ctypes.byref(crtverify))
2479
2367
        if crtverify.value != 0:
2480
2368
            gnutls.openpgp_crt_deinit(crt)
2481
 
            raise gnutls.CertificateSecurityError(code
2482
 
                                                  =crtverify.value)
 
2369
            raise gnutls.CertificateSecurityError("Verify failed")
2483
2370
        # New buffer for the fingerprint
2484
2371
        buf = ctypes.create_string_buffer(20)
2485
2372
        buf_len = ctypes.c_size_t()
2495
2382
        return hex_fpr
2496
2383
 
2497
2384
 
2498
 
class MultiprocessingMixIn:
 
2385
class MultiprocessingMixIn(object):
2499
2386
    """Like socketserver.ThreadingMixIn, but with multiprocessing"""
2500
2387
 
2501
2388
    def sub_process_main(self, request, address):
2513
2400
        return proc
2514
2401
 
2515
2402
 
2516
 
class MultiprocessingMixInWithPipe(MultiprocessingMixIn):
 
2403
class MultiprocessingMixInWithPipe(MultiprocessingMixIn, object):
2517
2404
    """ adds a pipe to the MixIn """
2518
2405
 
2519
2406
    def process_request(self, request, client_address):
2534
2421
 
2535
2422
 
2536
2423
class IPv6_TCPServer(MultiprocessingMixInWithPipe,
2537
 
                     socketserver.TCPServer):
 
2424
                     socketserver.TCPServer, object):
2538
2425
    """IPv6-capable TCP server.  Accepts 'None' as address and/or port
2539
2426
 
2540
2427
    Attributes:
2613
2500
                    raise
2614
2501
        # Only bind(2) the socket if we really need to.
2615
2502
        if self.server_address[0] or self.server_address[1]:
2616
 
            if self.server_address[1]:
2617
 
                self.allow_reuse_address = True
2618
2503
            if not self.server_address[0]:
2619
2504
                if self.address_family == socket.AF_INET6:
2620
2505
                    any_address = "::"  # in6addr_any
2694
2579
        command = request[0]
2695
2580
 
2696
2581
        if command == 'init':
2697
 
            key_id = request[1].decode("ascii")
2698
 
            fpr = request[2].decode("ascii")
2699
 
            address = request[3]
 
2582
            fpr = request[1].decode("ascii")
 
2583
            address = request[2]
2700
2584
 
2701
2585
            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:
 
2586
                if c.fingerprint == fpr:
2708
2587
                    client = c
2709
2588
                    break
2710
2589
            else:
2711
 
                logger.info("Client not found for key ID: %s, address"
2712
 
                            ": %s", key_id or fpr, address)
 
2590
                logger.info("Client not found for fingerprint: %s, ad"
 
2591
                            "dress: %s", fpr, address)
2713
2592
                if self.use_dbus:
2714
2593
                    # Emit D-Bus signal
2715
 
                    mandos_dbus_service.ClientNotFound(key_id or fpr,
 
2594
                    mandos_dbus_service.ClientNotFound(fpr,
2716
2595
                                                       address[0])
2717
2596
                parent_pipe.send(False)
2718
2597
                return False
2981
2860
        sys.exit(os.EX_OK if fail_count == 0 else 1)
2982
2861
 
2983
2862
    # 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
2863
    server_defaults = {"interface": "",
2991
2864
                       "address": "",
2992
2865
                       "port": "",
2993
2866
                       "debug": "False",
2994
 
                       "priority": priority,
 
2867
                       "priority":
 
2868
                       "SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP:!RSA"
 
2869
                       ":+SIGN-DSA-SHA256",
2995
2870
                       "servicename": "Mandos",
2996
2871
                       "use_dbus": "True",
2997
2872
                       "use_ipv6": "True",
3002
2877
                       "foreground": "False",
3003
2878
                       "zeroconf": "True",
3004
2879
                       }
3005
 
    del priority
3006
2880
 
3007
2881
    # Parse config file for server-global settings
3008
 
    server_config = configparser.ConfigParser(server_defaults)
 
2882
    server_config = configparser.SafeConfigParser(server_defaults)
3009
2883
    del server_defaults
3010
2884
    server_config.read(os.path.join(options.configdir, "mandos.conf"))
3011
 
    # Convert the ConfigParser object to a dict
 
2885
    # Convert the SafeConfigParser object to a dict
3012
2886
    server_settings = server_config.defaults()
3013
2887
    # Use the appropriate methods on the non-string config options
3014
2888
    for option in ("debug", "use_dbus", "use_ipv6", "restore",
3086
2960
                                  server_settings["servicename"])))
3087
2961
 
3088
2962
    # Parse config file with clients
3089
 
    client_config = configparser.ConfigParser(Client.client_defaults)
 
2963
    client_config = configparser.SafeConfigParser(Client
 
2964
                                                  .client_defaults)
3090
2965
    client_config.read(os.path.join(server_settings["configdir"],
3091
2966
                                    "clients.conf"))
3092
2967
 
3163
3038
        # Close all input and output, do double fork, etc.
3164
3039
        daemon()
3165
3040
 
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()
 
3041
    # multiprocessing will use threads, so before we use GLib we need
 
3042
    # to inform GLib that threads will be used.
 
3043
    GLib.threads_init()
3170
3044
 
3171
3045
    global main_loop
3172
3046
    # From the Avahi example code
3252
3126
                        for k in ("name", "host"):
3253
3127
                            if isinstance(value[k], bytes):
3254
3128
                                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
3129
                    #  old_client_settings
3260
3130
                    # .keys()
3261
3131
                    old_client_settings = {
3398
3268
                pass
3399
3269
 
3400
3270
            @dbus.service.signal(_interface, signature="ss")
3401
 
            def ClientNotFound(self, key_id, address):
 
3271
            def ClientNotFound(self, fingerprint, address):
3402
3272
                "D-Bus signal"
3403
3273
                pass
3404
3274