/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-10-29 14:22:26 UTC
  • Revision ID: teddy@recompile.se-20161029142226-n4s9d70tuk615pg1
Makefile: Clarify message when running client.

* Makefile (run-client): Clarify message.

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.13"
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."""
 
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."""
515
509
 
516
510
    library = ctypes.util.find_library("gnutls")
517
511
    if library is None:
518
512
        library = ctypes.util.find_library("gnutls-deb0")
519
513
    _library = ctypes.cdll.LoadLibrary(library)
520
514
    del library
 
515
    _need_version = b"3.3.0"
 
516
 
 
517
    def __init__(self):
 
518
        # Need to use "self" here, since this method is called before
 
519
        # the assignment to the "gnutls" global variable happens.
 
520
        if self.check_version(self._need_version) is None:
 
521
            raise self.Error("Needs GnuTLS {} or later"
 
522
                             .format(self._need_version))
521
523
 
522
524
    # Unless otherwise indicated, the constants and types below are
523
525
    # all from the gnutls/gnutls.h C header file.
527
529
    E_INTERRUPTED = -52
528
530
    E_AGAIN = -28
529
531
    CRT_OPENPGP = 2
530
 
    CRT_RAWPK = 3
531
532
    CLIENT = 2
532
533
    SHUT_RDWR = 0
533
534
    CRD_CERTIFICATE = 1
534
535
    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
536
    OPENPGP_FMT_RAW = 0         # gnutls/openpgp.h
541
537
 
542
538
    # Types
565
561
 
566
562
    # Exceptions
567
563
    class Error(Exception):
 
564
        # We need to use the class name "GnuTLS" here, since this
 
565
        # exception might be raised from within GnuTLS.__init__,
 
566
        # which is called before the assignment to the "gnutls"
 
567
        # global variable has happened.
568
568
        def __init__(self, message=None, code=None, args=()):
569
569
            # Default usage is by a message string, but if a return
570
570
            # code is passed, convert it to a string with
571
571
            # gnutls.strerror()
572
572
            self.code = code
573
573
            if message is None and code is not None:
574
 
                message = gnutls.strerror(code)
575
 
            return super(gnutls.Error, self).__init__(
 
574
                message = GnuTLS.strerror(code)
 
575
            return super(GnuTLS.Error, self).__init__(
576
576
                message, *args)
577
577
 
578
578
    class CertificateSecurityError(Error):
579
579
        pass
580
580
 
581
581
    # Classes
582
 
    class Credentials:
 
582
    class Credentials(object):
583
583
        def __init__(self):
584
584
            self._c_object = gnutls.certificate_credentials_t()
585
585
            gnutls.certificate_allocate_credentials(
589
589
        def __del__(self):
590
590
            gnutls.certificate_free_credentials(self._c_object)
591
591
 
592
 
    class ClientSession:
 
592
    class ClientSession(object):
593
593
        def __init__(self, socket, credentials=None):
594
594
            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
 
595
            gnutls.init(ctypes.byref(self._c_object), gnutls.CLIENT)
602
596
            gnutls.set_default_priority(self._c_object)
603
597
            gnutls.transport_set_ptr(self._c_object, socket.fileno())
604
598
            gnutls.handshake_set_private_extensions(self._c_object,
736
730
    check_version.argtypes = [ctypes.c_char_p]
737
731
    check_version.restype = ctypes.c_char_p
738
732
 
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
 
733
    # All the function declarations below are from gnutls/openpgp.h
 
734
 
 
735
    openpgp_crt_init = _library.gnutls_openpgp_crt_init
 
736
    openpgp_crt_init.argtypes = [ctypes.POINTER(openpgp_crt_t)]
 
737
    openpgp_crt_init.restype = _error_code
 
738
 
 
739
    openpgp_crt_import = _library.gnutls_openpgp_crt_import
 
740
    openpgp_crt_import.argtypes = [openpgp_crt_t,
 
741
                                   ctypes.POINTER(datum_t),
 
742
                                   openpgp_crt_fmt_t]
 
743
    openpgp_crt_import.restype = _error_code
 
744
 
 
745
    openpgp_crt_verify_self = _library.gnutls_openpgp_crt_verify_self
 
746
    openpgp_crt_verify_self.argtypes = [openpgp_crt_t, ctypes.c_uint,
 
747
                                        ctypes.POINTER(ctypes.c_uint)]
 
748
    openpgp_crt_verify_self.restype = _error_code
 
749
 
 
750
    openpgp_crt_deinit = _library.gnutls_openpgp_crt_deinit
 
751
    openpgp_crt_deinit.argtypes = [openpgp_crt_t]
 
752
    openpgp_crt_deinit.restype = None
 
753
 
 
754
    openpgp_crt_get_fingerprint = (
 
755
        _library.gnutls_openpgp_crt_get_fingerprint)
 
756
    openpgp_crt_get_fingerprint.argtypes = [openpgp_crt_t,
 
757
                                            ctypes.c_void_p,
 
758
                                            ctypes.POINTER(
 
759
                                                ctypes.c_size_t)]
 
760
    openpgp_crt_get_fingerprint.restype = _error_code
808
761
 
809
762
    # Remove non-public functions
810
763
    del _error_code, _retry_on_error
 
764
# Create the global "gnutls" object, simulating a module
 
765
gnutls = GnuTLS()
811
766
 
812
767
 
813
768
def call_pipe(connection,       # : multiprocessing.Connection
821
776
    connection.close()
822
777
 
823
778
 
824
 
class Client:
 
779
class Client(object):
825
780
    """A representation of a client host served by this server.
826
781
 
827
782
    Attributes:
828
783
    approved:   bool(); 'None' if not yet approved/disapproved
829
784
    approval_delay: datetime.timedelta(); Time to wait for approval
830
785
    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.
 
786
    checker:    subprocess.Popen(); a running checker process used
 
787
                                    to see if the client lives.
 
788
                                    'None' if no process is running.
834
789
    checker_callback_tag: a GLib event source tag, or None
835
790
    checker_command: string; External command which is run to check
836
791
                     if client lives.  %() expansions are done at
844
799
    disable_initiator_tag: a GLib event source tag, or None
845
800
    enabled:    bool()
846
801
    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
 
802
                 uniquely identify the client
850
803
    host:       string; available for use by the checker command
851
804
    interval:   datetime.timedelta(); How often to start a new checker
852
805
    last_approval_request: datetime.datetime(); (UTC) or None
870
823
    """
871
824
 
872
825
    runtime_expansions = ("approval_delay", "approval_duration",
873
 
                          "created", "enabled", "expires", "key_id",
 
826
                          "created", "enabled", "expires",
874
827
                          "fingerprint", "host", "interval",
875
828
                          "last_approval_request", "last_checked_ok",
876
829
                          "last_enabled", "name", "timeout")
906
859
            client["enabled"] = config.getboolean(client_name,
907
860
                                                  "enabled")
908
861
 
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(" ", ""))
 
862
            # Uppercase and remove spaces from fingerprint for later
 
863
            # comparison purposes with return value from the
 
864
            # fingerprint() function
914
865
            client["fingerprint"] = (section["fingerprint"].upper()
915
866
                                     .replace(" ", ""))
916
867
            if "secret" in section:
960
911
            self.expires = None
961
912
 
962
913
        logger.debug("Creating client %r", self.name)
963
 
        logger.debug("  Key ID: %s", self.key_id)
964
914
        logger.debug("  Fingerprint: %s", self.fingerprint)
965
915
        self.created = settings.get("created",
966
916
                                    datetime.datetime.utcnow())
1043
993
    def checker_callback(self, source, condition, connection,
1044
994
                         command):
1045
995
        """The checker has completed, so take appropriate actions."""
 
996
        self.checker_callback_tag = None
 
997
        self.checker = None
1046
998
        # Read return code from connection (see call_pipe)
1047
999
        returncode = connection.recv()
1048
1000
        connection.close()
1049
 
        self.checker.join()
1050
 
        self.checker_callback_tag = None
1051
 
        self.checker = None
1052
1001
 
1053
1002
        if returncode >= 0:
1054
1003
            self.last_checker_status = returncode
1511
1460
                         exc_info=error)
1512
1461
        return xmlstring
1513
1462
 
1514
 
 
1515
1463
try:
1516
1464
    dbus.OBJECT_MANAGER_IFACE
1517
1465
except AttributeError:
2049
1997
    def Name_dbus_property(self):
2050
1998
        return dbus.String(self.name)
2051
1999
 
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
2000
    # Fingerprint - property
2060
2001
    @dbus_annotations(
2061
2002
        {"org.freedesktop.DBus.Property.EmitsChangedSignal": "const"})
2216
2157
    del _interface
2217
2158
 
2218
2159
 
2219
 
class ProxyClient:
2220
 
    def __init__(self, child_pipe, key_id, fpr, address):
 
2160
class ProxyClient(object):
 
2161
    def __init__(self, child_pipe, fpr, address):
2221
2162
        self._pipe = child_pipe
2222
 
        self._pipe.send(('init', key_id, fpr, address))
 
2163
        self._pipe.send(('init', fpr, address))
2223
2164
        if not self._pipe.recv():
2224
 
            raise KeyError(key_id or fpr)
 
2165
            raise KeyError(fpr)
2225
2166
 
2226
2167
    def __getattribute__(self, name):
2227
2168
        if name == '_pipe':
2294
2235
 
2295
2236
            approval_required = False
2296
2237
            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,
 
2238
                try:
 
2239
                    fpr = self.fingerprint(
 
2240
                        self.peer_certificate(session))
 
2241
                except (TypeError, gnutls.Error) as error:
 
2242
                    logger.warning("Bad certificate: %s", error)
 
2243
                    return
 
2244
                logger.debug("Fingerprint: %s", fpr)
 
2245
 
 
2246
                try:
 
2247
                    client = ProxyClient(child_pipe, fpr,
2319
2248
                                         self.client_address)
2320
2249
                except KeyError:
2321
2250
                    return
2398
2327
 
2399
2328
    @staticmethod
2400
2329
    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)
 
2330
        "Return the peer's OpenPGP certificate as a bytestring"
 
2331
        # If not an OpenPGP certificate...
 
2332
        if (gnutls.certificate_type_get(session._c_object)
 
2333
            != gnutls.CRT_OPENPGP):
2415
2334
            # ...return invalid data
2416
2335
            return b""
2417
2336
        list_size = ctypes.c_uint(1)
2425
2344
        return ctypes.string_at(cert.data, cert.size)
2426
2345
 
2427
2346
    @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
2347
    def fingerprint(openpgp):
2463
2348
        "Convert an OpenPGP bytestring to a hexdigit fingerprint"
2464
2349
        # New GnuTLS "datum" with the OpenPGP public key
2478
2363
                                       ctypes.byref(crtverify))
2479
2364
        if crtverify.value != 0:
2480
2365
            gnutls.openpgp_crt_deinit(crt)
2481
 
            raise gnutls.CertificateSecurityError(code
2482
 
                                                  =crtverify.value)
 
2366
            raise gnutls.CertificateSecurityError("Verify failed")
2483
2367
        # New buffer for the fingerprint
2484
2368
        buf = ctypes.create_string_buffer(20)
2485
2369
        buf_len = ctypes.c_size_t()
2495
2379
        return hex_fpr
2496
2380
 
2497
2381
 
2498
 
class MultiprocessingMixIn:
 
2382
class MultiprocessingMixIn(object):
2499
2383
    """Like socketserver.ThreadingMixIn, but with multiprocessing"""
2500
2384
 
2501
2385
    def sub_process_main(self, request, address):
2513
2397
        return proc
2514
2398
 
2515
2399
 
2516
 
class MultiprocessingMixInWithPipe(MultiprocessingMixIn):
 
2400
class MultiprocessingMixInWithPipe(MultiprocessingMixIn, object):
2517
2401
    """ adds a pipe to the MixIn """
2518
2402
 
2519
2403
    def process_request(self, request, client_address):
2534
2418
 
2535
2419
 
2536
2420
class IPv6_TCPServer(MultiprocessingMixInWithPipe,
2537
 
                     socketserver.TCPServer):
 
2421
                     socketserver.TCPServer, object):
2538
2422
    """IPv6-capable TCP server.  Accepts 'None' as address and/or port
2539
2423
 
2540
2424
    Attributes:
2613
2497
                    raise
2614
2498
        # Only bind(2) the socket if we really need to.
2615
2499
        if self.server_address[0] or self.server_address[1]:
2616
 
            if self.server_address[1]:
2617
 
                self.allow_reuse_address = True
2618
2500
            if not self.server_address[0]:
2619
2501
                if self.address_family == socket.AF_INET6:
2620
2502
                    any_address = "::"  # in6addr_any
2694
2576
        command = request[0]
2695
2577
 
2696
2578
        if command == 'init':
2697
 
            key_id = request[1].decode("ascii")
2698
 
            fpr = request[2].decode("ascii")
2699
 
            address = request[3]
 
2579
            fpr = request[1]
 
2580
            address = request[2]
2700
2581
 
2701
2582
            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:
 
2583
                if c.fingerprint == fpr:
2708
2584
                    client = c
2709
2585
                    break
2710
2586
            else:
2711
 
                logger.info("Client not found for key ID: %s, address"
2712
 
                            ": %s", key_id or fpr, address)
 
2587
                logger.info("Client not found for fingerprint: %s, ad"
 
2588
                            "dress: %s", fpr, address)
2713
2589
                if self.use_dbus:
2714
2590
                    # Emit D-Bus signal
2715
 
                    mandos_dbus_service.ClientNotFound(key_id or fpr,
 
2591
                    mandos_dbus_service.ClientNotFound(fpr,
2716
2592
                                                       address[0])
2717
2593
                parent_pipe.send(False)
2718
2594
                return False
2981
2857
        sys.exit(os.EX_OK if fail_count == 0 else 1)
2982
2858
 
2983
2859
    # 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
2860
    server_defaults = {"interface": "",
2991
2861
                       "address": "",
2992
2862
                       "port": "",
2993
2863
                       "debug": "False",
2994
 
                       "priority": priority,
 
2864
                       "priority":
 
2865
                       "SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP:!RSA"
 
2866
                       ":+SIGN-DSA-SHA256",
2995
2867
                       "servicename": "Mandos",
2996
2868
                       "use_dbus": "True",
2997
2869
                       "use_ipv6": "True",
3002
2874
                       "foreground": "False",
3003
2875
                       "zeroconf": "True",
3004
2876
                       }
3005
 
    del priority
3006
2877
 
3007
2878
    # Parse config file for server-global settings
3008
 
    server_config = configparser.ConfigParser(server_defaults)
 
2879
    server_config = configparser.SafeConfigParser(server_defaults)
3009
2880
    del server_defaults
3010
2881
    server_config.read(os.path.join(options.configdir, "mandos.conf"))
3011
 
    # Convert the ConfigParser object to a dict
 
2882
    # Convert the SafeConfigParser object to a dict
3012
2883
    server_settings = server_config.defaults()
3013
2884
    # Use the appropriate methods on the non-string config options
3014
 
    for option in ("debug", "use_dbus", "use_ipv6", "restore",
3015
 
                   "foreground", "zeroconf"):
 
2885
    for option in ("debug", "use_dbus", "use_ipv6", "foreground"):
3016
2886
        server_settings[option] = server_config.getboolean("DEFAULT",
3017
2887
                                                           option)
3018
2888
    if server_settings["port"]:
3086
2956
                                  server_settings["servicename"])))
3087
2957
 
3088
2958
    # Parse config file with clients
3089
 
    client_config = configparser.ConfigParser(Client.client_defaults)
 
2959
    client_config = configparser.SafeConfigParser(Client
 
2960
                                                  .client_defaults)
3090
2961
    client_config.read(os.path.join(server_settings["configdir"],
3091
2962
                                    "clients.conf"))
3092
2963
 
3163
3034
        # Close all input and output, do double fork, etc.
3164
3035
        daemon()
3165
3036
 
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()
 
3037
    # multiprocessing will use threads, so before we use GLib we need
 
3038
    # to inform GLib that threads will be used.
 
3039
    GLib.threads_init()
3170
3040
 
3171
3041
    global main_loop
3172
3042
    # From the Avahi example code
3252
3122
                        for k in ("name", "host"):
3253
3123
                            if isinstance(value[k], bytes):
3254
3124
                                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
3125
                    #  old_client_settings
3260
3126
                    # .keys()
3261
3127
                    old_client_settings = {
3398
3264
                pass
3399
3265
 
3400
3266
            @dbus.service.signal(_interface, signature="ss")
3401
 
            def ClientNotFound(self, key_id, address):
 
3267
            def ClientNotFound(self, fingerprint, address):
3402
3268
                "D-Bus signal"
3403
3269
                pass
3404
3270